Problem B. Maximal Difference (Junior)
題意:給你一個n,讓你找出n位數中各個位數相加相等且差值最大的值。 比如n=2就是91和19,所以答案就是72
題解:直接一個個算出來或者找規律,n=2就是91和19,n=3就是910和109,n=4就是9910和1099。
代碼:
#include<cstdio>
int n;
int main(){
scanf("%d",&n);
switch(n){
case 1: printf("0\n");break;
case 2: printf("72\n");break;
case 3: printf("801\n");break;
case 4: printf("8811\n");break;
case 5: printf("89001\n");break;
case 6: printf("898101\n");break;
case 7: printf("8990001\n");break;
case 8: printf("89981001\n");break;
case 9: printf("899900001\n");break;
case 10: printf("8999810001\n");break;
}
return 0;
}
Problem D. Triangle Construction (Junior)
題意:給你三角形的三邊,若不能成爲三角形則輸出Impossible ,否則輸出三個點的座標(任意)。
題解:固定兩個點在x軸上,然後求出一個角的角度,用三角形正餘弦定理就能搞定了= =
代碼:
#include<cstdio>
#include<cmath>
const double eps=1e-7;
struct node{
double x,y;
}e[3];
double a,b,c;
double s;
int main(){
scanf("%lf%lf%lf",&a,&b,&c);
if(a+b-c<=eps||a+c-b<=eps||b+c-a<=eps){
printf("Impossible\n");
return 0;
}
e[0].x=e[0].y=0;
e[1].x=a;
e[1].y=0;
double s=acos((b*b+a*a-c*c)/(double)(2*a*b));
printf("%lf %lf\n",e[0].x,e[0].y);
printf("%lf %lf\n",e[1].x,e[1].y);
printf("%lf %lf\n",a-b*cos(s),b*sin(s));
return 0;
}
Problem F. Beautiful Patterns (Junior)
題意:給你一個n*m的地板和k塊已經知道顏色的單元地板,若是這個地板在所有的2*2的塊中都有3個白地板和1個黑地板或3個黑地板和1個白地板,則這個n*m的地板則爲beautiful,求有多少種方法能使得這個n*m的地板爲beautiful
題解:由於n,m較小,因此我們先枚舉第一行的所有情況,最多有1024種情況(要排除不行的,題目給你是白色的,你卻用黑色填充這種情況)。然後對於下一行,我們假設第一塊是白色或者黑色的可能,然後從第二塊開始枚舉,就可以得到精確的這一行各塊的顏色了,我們用mp[i][j]記錄方法到第i行第j種方法的方案數,最後我們會得到這麼一個遞推公式:mp[i][ss]=(mp[i][ss]+mp[i-1][j])%mod。最後ans=∑mp[n-1][0->2^(m-1)]
代碼:
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
ll n,m,k,x,y,z,flag,ss;
ll mp[15][1111],mmp[15][15];
ll s[15][15],ans,sa[15];
struct node{
ll x,y,z;
}e[105];
int main(){
scanf("%lld%lld%lld",&n,&m,&k);
for(ll i=0;i<=10;i++)
for(ll j=0;j<=10;j++) s[i][j]=-1;
for(ll i=0;i<k;i++){
scanf("%lld%lld%lld",&x,&y,&z);
s[x-1][y-1]=z;
}
sa[0]=1;
for(ll i=1;i<=10;i++) sa[i]=sa[i-1]*2;
for(ll i=0;i<sa[m];i++){
flag=1;
for(ll j=0;j<m;j++){
if(s[0][j]!=-1&&((i>>j)%2)!=s[0][j]){
flag=0;
break;
}
}
if(flag) mp[0][i]=1;
}
for(ll i=1;i<n;i++){
for(ll j=0;j<sa[m];j++){
if(mp[i-1][j]==0) continue;
for(ll k=0;k<m;k++) mmp[i-1][k]=(j>>k)%2;
mmp[i][0]=0; //最前面爲0的情況
for(ll k=1;k<m;k++){
ll a0=0,a1=0;
if(mmp[i][k-1]==0) a0++;
if(mmp[i-1][k-1]==0) a0++;
if(mmp[i-1][k]==0) a0++;
if(a0==0||a0==2) mmp[i][k]=0;
else mmp[i][k]=1;
}
flag=1;
for(ll k=0;k<m;k++){
if(s[i][k]!=-1&&s[i][k]!=mmp[i][k]){
flag=0;
break;
}
}
if(flag){
ss=0;
for(ll k=m-1;k>=0;k--) ss=ss*2+mmp[i][k];
mp[i][ss]=(mp[i][ss]+mp[i-1][j])%mod;
}
mmp[i][0]=1; //最前面爲1的情況
for(ll k=1;k<m;k++){
ll a0=0,a1=0;
if(mmp[i][k-1]==0) a0++;
if(mmp[i-1][k-1]==0) a0++;
if(mmp[i-1][k]==0) a0++;
if(a0==0||a0==2) mmp[i][k]=0;
else mmp[i][k]=1;
}
flag=1;
for(ll k=0;k<m;k++){
if(s[i][k]!=-1&&s[i][k]!=mmp[i][k]){
flag=0;
break;
}
}
if(flag){
ss=0;
for(ll k=m-1;k>=0;k--) ss=ss*2+mmp[i][k];
mp[i][ss]=(mp[i][ss]+mp[i-1][j])%mod;
}
}
}
for(ll i=0;i<sa[m];i++) ans=(ans+mp[n-1][i])%mod;
printf("%lld\n",ans);
return 0;
}
Problem H. String without repetitions (Junior)
題意:讓你求一個長度爲n的字符串,長度爲k的任意兩個相鄰子串都不能相同(k爲任意),且字典序最小。
題解:由於任意兩個相鄰子串都不能相同,所以我們要分割這個串,因此我們能先把1的倍數的位置先放入a,然後在2的倍數的位置放入b,再在4的倍數的位置放入c,按照這個規律即可求出這個長度爲n的字符串。
代碼:
#include<cstdio>
#include<cstring>
int n,a[30],s;
char st[4000005];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) st[i]='a';
a[0]=1;
for(int i=1;i<30;i++){
a[i]=a[i-1]*2;
if(a[i]>=n){
s=i;break;
}
}
for(int i=1;i<=s;i++){
for(int j=a[i];j<=n;j+=a[i]){
st[j]='a'+i;
}
}
printf("%s\n",st+1);
return 0;
}
Problem J. Beans gathering (Junior)
題意:給你n個盒子和每個盒子中豆子的個數,第i個可以將i的倍數個豆子放入第i-1個,問你最後能不能把所有豆子放到第0個盒子
題解:從後向前for一遍就可以了= =,如果遇到一個盒子的豆子無法被i除盡,則輸出no,否則將這些豆子放到第i-1個盒子。
代碼:
#include<cstdio>
#include<cstring>
int n,a[30],s;
char st[4000005];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) st[i]='a';
a[0]=1;
for(int i=1;i<30;i++){
a[i]=a[i-1]*2;
if(a[i]>=n){
s=i;break;
}
}
for(int i=1;i<=s;i++){
for(int j=a[i];j<=n;j+=a[i]){
st[j]='a'+i;
}
}
printf("%s\n",st+1);
return 0;
}
Problem L. Reverse beans gathering (Junior)
題意:給你n個豆子,讓你放在各個盒子裏,移動方法如上題,問你輸出最小字典序的豆子放法(最小字典序定義看題)
題解:將n個豆子從第0個盒子到1,2,3模擬,直到豆子用完爲止即可。
例: 7個豆子。
7%1==0,所以變成0 7
7%2==0,所以變成0 1 6
6%3==0,所以變成0 1 0 6
6%4==2,所以變成0 1 0 2 4 到此豆子用完。
代碼:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,a[100005],flag=1;
int main(){
scanf("%lld",&n);
for(ll i=0;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=n;i>0;i--){
if(a[i]%i==0) a[i-1]+=a[i];
else{
flag=0;
break;
}
}
if(flag) printf("Yes\n");
else printf("No\n");
return 0;
}
Problem N. Equation (Junior)
題意:給你多項式的係數,求滿足等式的最小x
題解:這題可以轉化爲,是否存在x滿足多項式是p*2的倍數,那就可以枚舉x,由於循環節是2014*2014,所以最多循環2014*2014次。
代碼:
#include<bits/stdc++.h>
typedef long long ll;
ll n,a[25],p,flag,ans;
int main(){
scanf("%lld%lld",&p,&n);
for(ll i=n;i>=0;i--) scanf("%lld",&a[i]);
ll pp=p*p;
for(ll i=0;i<=pp;i++){
ll sum=0,s=1;
for(ll j=0;j<=n;j++){
sum=(sum+s*a[j])%pp;
s=(s*i)%pp;
}
if(sum==0){
ans=i;
flag=1;
break;
}
}
if(flag) printf("%lld\n",ans);
else printf("-1\n");
return 0;
}
Problem P. Competition (Junior)
題意:給你兩個數列,他們的數字是1->2*n,每個數都不相同,然後每次第一個人從第一個數列選一個數,第二個人從第二個數列選一個數,問第二個人能贏的次數最多是多少次。
題解:把第二個人的數放入數組,然後貪心即可(不會的可以去看看田忌賽馬)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[400005],x,sum,ans;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&x);
for(int i=0;i<n;i++){
scanf("%d",&x);
a[x]=1;
}
for(int i=1;i<=2*n;i++){
if(a[i]==0) sum++;
else{
if(sum>0){
ans++;
sum--;
}
}
}
printf("%d\n",ans);
return 0;
}
Problem R. The incircle (Junior)
題意:給你一個凸多邊形,求內含的圓的最大半徑。
題解:半平面交模板題,首先二分邊向內延伸的長度,對於每個長度,我們通過半平面交,判斷是否存在內核,若存在內核,則存在該半徑(也就是向內延伸的長度),增大半徑,反之亦然。 代碼:
#include<iostream>
#include <stdio.h>
#include <math.h>
#define eps 1e-8
using namespace std;
const int MAXN=105;
int m;
double r;
int cCnt,curCnt;//此時cCnt爲最終切割得到的多邊形的頂點數、暫存頂點個數
struct point
{
double x,y;
};
point points[MAXN],p[MAXN],q[MAXN];//讀入的多邊形的頂點(順時針)、p爲存放最終切割得到的多邊形頂點的數組、暫存核的頂點
void getline(point x,point y,double &a,double &b,double &c){//兩點x、y確定一條直線a、b、c爲其係數
a = y.y - x.y;
b = x.x - y.x;
c = y.x * x.y - x.x * y.y;
}
void initial(){
for(int i = 1; i <= m; ++i)p[i] = points[i];
p[m+1] = p[1];
p[0] = p[m];
cCnt = m;//cCnt爲最終切割得到的多邊形的頂點數,將其初始化爲多邊形的頂點的個數
}
point intersect(point x,point y,double a,double b,double c){//求x、y形成的直線與已知直線a、b、c、的交點
double u = fabs(a * x.x + b * x.y + c);
double v = fabs(a * y.x + b * y.y + c);
point pt;
pt.x=(x.x * v + y.x * u) / (u + v);
pt.y=(x.y * v + y.y * u) / (u + v);
return pt;
}
void cut(double a,double b ,double c){
curCnt = 0;
for(int i = 1; i <= cCnt; ++i){
if(a*p[i].x + b*p[i].y + c >= 0)q[++curCnt] = p[i];// c由於精度問題,可能會偏小,所以有些點本應在右側而沒在,
//故應該接着判斷
else {
if(a*p[i-1].x + b*p[i-1].y + c > 0){//如果p[i-1]在直線的右側的話,
//則將p[i],p[i-1]形成的直線與已知直線的交點作爲核的一個頂點(這樣的話,由於精度的問題,核的面積可能會有所減少)
q[++curCnt] = intersect(p[i],p[i-1],a,b,c);
}
if(a*p[i+1].x + b*p[i+1].y + c > 0){//原理同上
q[++curCnt] = intersect(p[i],p[i+1],a,b,c);
}
}
}
for(int i = 1; i <= curCnt; ++i)p[i] = q[i];//將q中暫存的核的頂點轉移到p中
p[curCnt+1] = q[1];p[0] = p[curCnt];
cCnt = curCnt;
}
int solve(){
//注意:默認點是順時針,如果題目不是順時針,規整化方向
initial();
/*for(int i = 1; i <= m; ++i){
double a,b,c;
getline(points[i],points[i+1],a,b,c);
cut(a,b,c);
} */
//如果要向內推進r,用該部分代替上個函數
for(int i = 1; i <= m; ++i){
point ta, tb, tt;
tt.x = points[i+1].y - points[i].y;
tt.y = points[i].x - points[i+1].x;
double k = r / sqrt(tt.x * tt.x + tt.y * tt.y);
tt.x = tt.x * k;
tt.y = tt.y * k;
ta.x = points[i].x + tt.x;
ta.y = points[i].y + tt.y;
tb.x = points[i+1].x + tt.x;
tb.y = points[i+1].y + tt.y;
double a,b,c;
getline(ta,tb,a,b,c);
cut(a,b,c);
}
/* //多邊形核的面積
double area = 0;
for(int i = 1; i <= curCnt; ++i)
area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y;
area = fabs(area / 2.0);
*/ if(cCnt<=0)return 0;
return 1;
}
void GuiZhengHua(){
//規整化方向,逆時針變順時針,順時針變逆時針
for(int i = 1; i < (m+1)/2; i ++)
swap(points[i], points[m-i]);
}
int main()
{
scanf("%d",&m);
for(int i=1;i<=m;i++)
scanf("%lf%lf",&points[i].x,&points[i].y);
double x1=points[0].x,x2=points[1].x,x3=points[2].x,y1=points[0].y,y2=points[1].y,y3=points[2].y;
if((x2-x1)*(y3-y2)-(y2-y1)*(x3-x2)>0)
{
GuiZhengHua();
} points[m+1] = points[1];
double high = 2000000;
double low = 0,mid;
while(low + eps <= high){
mid = (high + low)/2.0;
r=mid;
if(solve())low = mid;
else high = mid;
}
printf("%lf\n",high);
}
Problem T. The dividing line (Junior)
題意:給你n個點,m條直線,對於每條直線,求是否有兩個點在不同側。
題解:n*m暴力判斷點與直線的關係。
代碼:
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
ll n,m,x1,x2,y1,y2,a,b;
struct node{
ll x,y;
}e[10005];
ll cal(ll x,ll y){
return (y2-y1)*(x-x1)-(y-y1)*(x2-x1);
}
int main(){
scanf("%lld",&n);
for(ll i=1;i<=n;i++) scanf("%lld%lld",&e[i].x,&e[i].y);
scanf("%lld",&m);
while(m--){
a=0;
b=0;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
for(ll j=1;j<=n;j++){
if(cal(e[j].x,e[j].y)>0&&a==0) a=j;
else if(cal(e[j].x,e[j].y)<0&&b==0) b=j;
if(a!=0&&b!=0){
printf("%lld %lld\n",min(a,b),max(a,b));
break;
}
}
if(a==0||b==0) printf("0\n");
}
return 0;
}
Problem V. Stringangulation (Junior)
題意:給你一個環形的串,求分割三次後,得到a,b,c三個串。問有多少分割滿足a+b>c&&a+c>b&&b+c>a(這裏是字符串比較與字符串拼接)
題解:n^4暴力分割比較
代碼:
#include<bits/stdc++.h>
using namespace std;
vector<int>p[300];
string st;
string a,b,c;
int ans;
int main(){
cin>>st;
for(int i=0;i<st.size();i++) p[st[i]].push_back(i);
for(int i=0;i<256;i++){
if(p[i].size()>=3){
for(int j=0;j<p[i].size();j++){
for(int k=j+1;k<p[i].size();k++){
for(int kk=k+1;kk<p[i].size();kk++){
a.clear();
b.clear();
c.clear();
for(int ss=p[i][j];ss!=p[i][k];ss=(ss+1)%st.size()) a+=st[ss];
for(int ss=p[i][k];ss!=p[i][kk];ss=(ss+1)%st.size()) b+=st[ss];
for(int ss=p[i][kk];ss!=p[i][j];ss=(ss+1)%st.size()) c+=st[ss];
if(a+b>c&&b+c>a&&c+a>b) ans++;
}
}
}
}
}
cout<<ans<<endl;
return 0;
}