2015 Syrian Private Universities Collegiate Programming Contest 题解
发现这场比赛在网上没有完整的题解,甚至连题目代码都没人贴出来(大概是因为题目太水了吧。。。)。所以宝宝就来写个题解,也就当作成长记录了233333
A. Window
题意很简单,给出n组x,y,求x*y的值
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 int main() 5 { 6 int n; 7 long long x,y; 8 scanf("%d",&n); 9 while(n--) 10 { 11 scanf("%I64d%I64d",&x,&y); 12 printf("%I64d\n",x*y); 13 } 14 return 0; 15 }
B. Paper Game
两个人撕纸片玩,会发现其实能够撕的次数就是x*y,所以就很简单啦^_^
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 int main() 5 { 6 int t; 7 int x,y; 8 scanf("%d",&t); 9 while(t--) 10 { 11 scanf("%d%d",&x,&y); 12 if((x*y)&1) 13 printf("Hussain\n"); 14 else 15 printf("Hasan\n"); 16 } 17 return 0; 18 }
C. Rectangles
计数,由于数据范围比较小,O(n)就能过了,根本不需要树状数组线段树神马的。把题目改为输入i,j,k,s再把数据范围改大一点,就需要二维树状数组了。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int Nmax=105; 5 int high[Nmax]; 6 int t,n,z,x,y,ans; 7 void init() 8 { 9 ans=0; 10 for(int i=0;i<Nmax;i++) 11 high[i]=0; 12 13 } 14 15 int main() 16 { 17 //freopen("c.in","r",stdin); 18 scanf("%d",&t); 19 while(t--) 20 { 21 init(); 22 scanf("%d",&n); 23 while(n--) 24 { 25 scanf("%d%d%d",&z,&x,&y); 26 for(int i=z+1;i<=x;i++) 27 high[i]=max(high[i],y); 28 } 29 for(int i=1;i<Nmax;i++) 30 ans+=high[i]; 31 printf("%d\n",ans); 32 } 33 return 0; 34 }
D. Sequences
求元素间恰好只差1的最长上升子序列,英语渣表示读题的时候没读懂一定要只差1,然后各种看不懂样例2333333 我们知道条件限制越多就越好写,所以必须只差1的话,用dp[i]记录到值为i的元素的最长上升子序列,因此dp[i]=max(dp[i],dp[i-1]+1),O(n)水过。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int Nmax=20005; 5 int dp[Nmax]; 6 int t,n,x,ans; 7 int main() 8 { 9 //freopen("d.in","r",stdin); 10 scanf("%d",&t); 11 while(t--) 12 { 13 scanf("%d",&n); 14 ans=0; 15 for(int i=0;i<Nmax;i++) 16 dp[i]=0; 17 for(int i=1;i<=n;i++) 18 { 19 scanf("%d",&x); 20 dp[x]=max(dp[x],dp[x-1]+1); 21 ans=max(ans,dp[x]); 22 } 23 printf("%d\n",ans); 24 } 25 return 0; 26 }
E. Napoléon
问在8*8的棋盘上,一个只能斜着走的棋子从某点到另一点的最小步数。
只能斜着走的话,显然(x+y)的奇偶性相同才能互相到达。虽然是斜着走,但是每次都能向目标方向靠近一个单位,所以最小步数就是max(|x1-x2|,|y1-y2|) 。
1 #include <cstdio> 2 #include <algorithm> 3 #include <queue> 4 using namespace std; 5 const int Nmax=25; 6 int dis[Nmax][Nmax]; 7 int n,t; 8 int xs,ys,xe,ye; 9 int get_num(int x,int y) 10 { 11 return (x-1)*n+y; 12 } 13 int abs(int x) 14 { 15 if(x<0) 16 return -x; 17 return x; 18 } 19 int main() 20 { 21 //freopen("e.in","r",stdin); 22 scanf("%d%d",&t,&n); 23 while(t--) 24 { 25 scanf("%d%d%d%d",&xs,&ys,&xe,&ye); 26 xs++,ys++,xe++,ye++; 27 // printf("%d %d %d %d\n",xs,ys,xe,ye); 28 // printf("%d %d\n",(xs+ys)&1,(xe+ye)&1); 29 if( ((xs+ys)&1)!=((xe+ye)&1) ) 30 printf("can't reach!\n"); 31 else 32 printf("%d\n",max( abs(xs-xe),abs(ys-ye) )); 33 } 34 return 0; 35 }
F. The Best Strategy
又死在了英语上ψ(╰_╯) 做了这题我才知道罚时是怎么算的。。。然而题目里没告诉罚时怎么算,所以又是看不懂样例系列。原来总罚时就是每道题在比赛中的完成时间之和。所以排个序模拟一下就好了。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int Nmax=305; 5 int num[Nmax]; 6 int sum,ans,number,now; 7 void init() 8 { 9 sum=ans=number=now=0; 10 } 11 12 int main() 13 { 14 int t,n; 15 //freopen("f.in","r",stdin); 16 scanf("%d",&t); 17 for(int k=1;k<=t;k++) 18 { 19 scanf("%d",&n); 20 init(); 21 for(int i=1;i<=n;i++) 22 scanf("%d",&num[i]); 23 sort(num+1,num+n+1); 24 for(int i=1;i<=n;i++) 25 { 26 if(now+num[i]<=300) 27 { 28 now=now+num[i]; 29 sum+=now; 30 number++; 31 } 32 else 33 break; 34 } 35 printf("Case %d: %d %d\n",k,number,sum); 36 } 37 }
G. Cutie Pie
找到一堆字符里面的“pie”,思路很简单,暴力BFS就好啦~
1 #include <cstdio> 2 #include <algorithm> 3 #include <queue> 4 using namespace std; 5 const int Nmax=25; 6 char map[Nmax][Nmax]; 7 int t,n,m,nowx,nowy,kkk,nowxx,nowyy; 8 int dx[]={-1,-1,-1, 0,0, 1,1,1}; 9 int dy[]={-1, 0, 1,-1,1,-1,0,1}; 10 struct Node 11 { 12 int x; 13 int y; 14 }p; 15 queue<Node> q; 16 17 int get_num(int x,int y) 18 { 19 return (x-1)*m+y; 20 } 21 22 void init() 23 { 24 while(!q.empty()) 25 q.pop(); 26 } 27 28 int main() 29 { 30 //freopen("g.in","r",stdin); 31 scanf("%d",&t); 32 while(t--) 33 { 34 scanf("%d%d",&n,&m); 35 init(); 36 for(int i=1;i<=n;i++) 37 { 38 for(int j=1;j<=m;j++) 39 { 40 getchar(); 41 map[i][j]=getchar(); 42 if(map[i][j]=='p') 43 q.push((Node){i,j}); 44 } 45 } 46 // for(int i=1;i<=n;i++) 47 // { 48 // for(int j=1;j<=m;j++) 49 // printf("%c ",map[i][j]); 50 // printf("\n"); 51 // } 52 // while(!q.empty()) 53 // { 54 // p=q.front(); 55 // q.pop(); 56 // printf("%d %d\n",p.x,p.y); 57 // } 58 int ans=0; 59 while(!q.empty()) 60 { 61 if(ans) 62 break; 63 p=q.front(); 64 q.pop(); 65 for(int i=0;i<8;i++) 66 { 67 if(ans) 68 break; 69 nowx=p.x+dx[i],nowy=p.y+dy[i]; 70 kkk=get_num(nowx,nowy); 71 if(kkk>=1 && kkk<=n*m && map[nowx][nowy]=='i') 72 { 73 for(int j=0;j<8;j++) 74 { 75 nowxx=nowx+dx[j],nowyy=nowy+dy[j]; 76 kkk=get_num(nowxx,nowyy); 77 if(kkk>=1 && kkk<=n*m && map[nowxx][nowyy]=='e') 78 { 79 ans=1; 80 break; 81 } 82 } 83 } 84 } 85 } 86 if(ans) 87 printf("Cutie Pie!\n"); 88 else 89 printf("Sorry Man\n"); 90 } 91 return 0; 92 }
H. Weekend
问一个人从起点到终点接上所有朋友的最短时间。先把每两个点间的最短距离求出来,再对所有的朋友点跑一个记忆化搜索。因为朋友数很少,状态压缩一下记录所有的状态,再用dp[i][j]记录到点i时状态j的最短时间,就搞定啦ヾ(*´▽‘*)ノ 然而我居然漏写了一个等号,然后一直TLE 23333
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int Nmax=1005; 5 const int INF=1e9; 6 int ans,ans_min; 7 int dis[Nmax][Nmax]; 8 int map[Nmax][Nmax]; 9 int x,y,w,n,m,f; 10 int num[Nmax]; 11 int book[Nmax],step; 12 13 void init() 14 { 15 ans=0; 16 step=0; 17 ans_min=INF; 18 for(int i=1;i<=n;i++) 19 for(int j=1;j<=n;j++) 20 dis[i][j]=INF; 21 for(int i=1;i<=n;i++) 22 dis[i][i]=num[i]=book[i]=0; 23 } 24 25 void dfs(int now) 26 { 27 if(now==f+2) 28 { 29 if(step==f+2) 30 ans_min=min(ans_min,ans); 31 return; 32 } 33 34 for(int i=1;i<=f+2;i++) 35 { 36 if(dis[num[now]][num[i]]<INF) 37 { 38 if(!book[i]) 39 { 40 ans+=dis[num[now]][num[i]]; 41 step++; 42 book[i]=1; 43 dfs(i); 44 ans-=dis[num[now]][num[i]]; 45 step--,book[i]=0; 46 } 47 else 48 { 49 ans+=dis[num[now]][num[i]]; 50 dfs(i); 51 ans-=dis[num[now]][num[i]]; 52 } 53 54 } 55 } 56 } 57 58 int main() 59 { 60 freopen("h.in","r",stdin); 61 int t; 62 scanf("%d",&t); 63 for(int k=1;k<=t;k++) 64 { 65 scanf("%d%d%d",&n,&m,&f); 66 init(); 67 printf("Case %d: \n",k); 68 while(m--) 69 { 70 scanf("%d%d%d",&x,&y,&w); 71 dis[x][y]=dis[y][x]=map[x][y]=map[y][x]=w; 72 } 73 for(int tmp=1;tmp<=n;tmp++) 74 { 75 for(int i=1;i<=n;i++) 76 { 77 for(int j=1;j<=n;j++) 78 { 79 if(dis[i][tmp]+dis[tmp][j]<dis[i][j]) 80 dis[i][j]=dis[i][tmp]+dis[tmp][j]; 81 } 82 } 83 } 84 num[1]=1; 85 book[1]=1,step++; 86 for(int i=2;i<=f+1;i++) 87 scanf("%d",&num[i]); 88 num[f+2]=n; 89 dfs(1); 90 printf("%d\n",ans_min); 91 } 92 return 0; 93 }
I. Playing With Strings
模拟模拟!
1 #include <cstdio> 2 #include <algorithm> 3 #include <string.h> 4 using namespace std; 5 const int Nmax=1005; 6 char ans[Nmax]; 7 int n,t,now; 8 int num[26]; 9 char s[Nmax]; 10 char c; 11 void init() 12 { 13 now=1; 14 for(int i=0;i<=n+1;i++) 15 ans[i]='\0'; 16 for(int i=0;i<26;i++) 17 num[i]=0; 18 for(int i=0;i<n;i++) 19 { 20 c=s[i]; 21 num[c-'a']++; 22 } 23 int ct=0; 24 for(int i=0;i<26;i++) 25 { 26 if(num[i]&1) 27 ct++; 28 } 29 if(ct>1) 30 { 31 printf("impossible\n"); 32 return; 33 } 34 for(int i=0;i<26;i++) 35 { 36 int kkkk=1; 37 kkkk=0; 38 if(num[i]&1) 39 ans[(n>>1)+1]=i+'a',num[i]--; 40 while( (num[i]-2)>=0 ) 41 { 42 ans[now]=ans[n+1-now]=i+'a'; 43 num[i]-=2; 44 now++; 45 } 46 47 } 48 puts(ans+1); 49 } 50 51 int main() 52 { 53 //freopen("i.in","r",stdin); 54 scanf("%d",&t); 55 getchar(); 56 while(t--) 57 { 58 scanf("%s",s); 59 n=strlen(s); 60 init(); 61 } 62 return 0; 63 }
J. Good Coins
求gcd(i,j)是否为1。所以标程当然是gcd了,然而数据太水,所以用超慢超蠢的无限减法写法过了23333
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 int x,y; 5 int t; 6 7 int make(int a,int b) 8 { 9 if(a<0 || b<0) 10 return 0; 11 if(a==1 || b==1) 12 return 1; 13 if(a<b) 14 return make(b,a); 15 if(a==b) 16 return 0; 17 return make(a-b,b); 18 } 19 20 int main() 21 { 22 //freopen("j.in","r",stdin); 23 scanf("%d",&t); 24 while(t--) 25 { 26 scanf("%d%d",&x,&y); 27 if(make(x,y)) 28 printf("GOOD\n"); 29 else 30 printf("NOT GOOD\n"); 31 } 32 return 0; 33 }
K. Clash Of Snakes
求在n*m的格子上,1*s和1*k的长条互不重叠的摆法个数。原问题是有方向的,但是没关系,我们只要在没方向的方案数上乘4就是答案了。
用容斥原理,先求出来单独摆s和摆k的个数,再求出重叠的个数,一减就是答案了。然而要注意的是,模运算中,模完再做减法可能会出负数,所以最后要特判一下(就是因为这个负数,一直wa在第二个点,呜呜呜)。
由于本人比较懒,所以写了ll类型用来求模,虽然在相同写法上速度可能会慢点,但是容易检查而且不易写错,还是值得的。最终还是只有15ms就通过啦ヾ(o◕∀◕)ノヾ
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int Mod=1000000007; 5 6 struct ll 7 { 8 long long x; 9 ll() {x=0;} 10 ll(long long tttt) {x=tttt;} 11 12 ll operator + (ll b) 13 { 14 ll c; 15 c.x=(x+b.x)%Mod; 16 return c; 17 } 18 19 ll operator * (ll b) 20 { 21 ll c; 22 c.x=(x*b.x)%Mod; 23 return c; 24 } 25 26 ll operator -(ll b) 27 { 28 ll c; 29 c.x=(x-b.x)%Mod; 30 return c; 31 } 32 33 }; 34 35 ll get(ll n,ll m,ll k) 36 { 37 ll get_value(0); 38 if(k.x<=m.x && k.x<=n.x) 39 return (m-k+1)*n + (n-k+1)*m; 40 if(k.x>m.x && k.x<=n.x) 41 return (n-k+1)*m; 42 if(k.x>n.x && k.x<=m.x) 43 return (m-k+1)*n; 44 return get_value; 45 46 } 47 48 ll max(ll a,ll b) 49 { 50 if(a.x>=b.x) 51 return a; 52 else 53 return b; 54 } 55 56 ll min(ll a,ll b) 57 { 58 if(a.x<=b.x) 59 return a; 60 else 61 return b; 62 } 63 64 int main() 65 { 66 //freopen("k.in","r",stdin); 67 int t; 68 ll two(2),four(4),one(1),eight(8); 69 scanf("%d",&t); 70 long long tmpn,tmpm,tmps,tmpk; 71 for(int i=1;i<=t;i++) 72 { 73 scanf("%I64d%I64d%I64d%I64d",&tmpn,&tmpm,&tmps,&tmpk); 74 ll n(tmpn),m(tmpm),s(tmps),k(tmpk); 75 ll l=max(k,s); 76 ll r=min(k,s); 77 ll ans=(two*m*n-(m+n)*(k-one))*(two*m*n-(m+n)*(s-one)); 78 ll a=min(m,k+s-one); 79 ll b=min(n,k+s-one); 80 ans=ans-k*s*( (n-s+one)*(m-k+one)+(n-k+one)*(m-s+one) ); 81 ans=ans-(m-l+one)*n*(l-r+one)-(n-l+one)*m*(l-r+one); 82 ans=ans-n*(a-l)*( two*(m+one)-(a+l+one) ); 83 ans=ans-m*(b-l)*( two*(n+one)-(b+l+one) ); 84 ans=ans*four; 85 if(ans.x<0) 86 ans.x+=Mod; 87 printf("Case %d: %I64d\n",i,ans.x); 88 } 89 return 0; 90 }