【周赛题解】三
A. Playing with Paper
解法用辗转相除法,一边求出最大公约数,一边求出可分割的正方形的数量。
#include<stdio.h> #include<math.h> using namespace std; typedef long long ll; ll ans=0; ll gcd(ll a,ll b) { if(b==0) return a; else { ans+=a/b; return gcd(b,a%b); } } int main() { ll a,b; scanf("%I64d%I64d",&a,&b); gcd(a,b); printf("%I64d\n",ans); return 0; }
B. Error Correct System
用二维数组标记一下转换表再查找就可以啦
a[i][j]表示字符i转换为字符j的第一个位置
如果a[i][j]和a[j][i]都有需要转换的话,就交换这两个位置,否则查找如a[i][j],a[j][k]的形式交换,否则不能交换。
#include<stdio.h> #include<math.h> #include<string.h> using namespace std; int len; char s1[200005],s2[200005]; int a1[26][26]; int main() { int i,j,ii; memset(a1,-1,sizeof(a1)); scanf("%d",&len); getchar(); gets(s1); gets(s2); int k=0; for(i=0;i<len;i++) { if(s1[i]!=s2[i]) { a1[s1[i]-'a'][s2[i]-'a']=i; k++; } } int ans1=-1,ans2=-1; /*for(i=0;i<len;i++) { if(a1[i]&&a2[i]) { ans1=a1[i]; ans2=a2[i]; } }*/ for(i=0;i<26;i++) { for(j=i+1;j<26;j++) { if(a1[i][j]!=-1&&a1[j][i]!=-1) { ans1=a1[i][j];ans2=a1[j][i]; break; } } if(j<26) break; } if(ans1!=-1) { printf("%d\n",k-2); printf("%d %d\n",ans1+1,ans2+1); } else { for(i=0;i<26;i++) { for(j=0;j<26;j++) { if(a1[i][j]!=-1) { for(ii=0;ii<26;ii++) { if(a1[j][ii]!=-1) { ans1=a1[i][j]; ans2=a1[j][ii]; break; } } if(ii<26) break; } } if(j<26) break; } if(ans1!=-1) { printf("%d\n",k-1); printf("%d %d\n",ans1+1,ans2+1); } else { printf("%d\n",k); printf("-1 -1\n"); } } return 0; }
C. Glass Carving
本题要使用特殊的数据结构。
维护横向和纵向的最大宽度,查询时想乘即可。
#include<stdio.h> #include<math.h> #include<set> #include<map> using namespace std; set<int> H,V; map<int,int> HH,VV; int main() { int w,h,n,z; char c; scanf("%d%d%d",&w,&h,&n); H.insert(0); H.insert(h); V.insert(0); V.insert(w); HH[h]=1; VV[w]=1; while(n--) { int w; getchar(); scanf("%c%d",&c,&z); if(c=='H') { H.insert(z); { int l,r; set<int>::iterator it; it=H.find(z); it--; l=*it; it++; it++; r=*it; HH[r-l]--; if(HH[r-l]==0) { HH.erase(r-l); } HH[z-l]++; HH[r-z]++; printf("%I64d\n",(long long)(HH.rbegin()->first) *(VV.rbegin()->first) ); } } else { V.insert(z); { int l,r; set<int>::iterator it; it=V.find(z); it--; l=*it; it++; it++; r=*it; VV[r-l]--; if(VV[r-l]==0) { VV.erase(r-l); } VV[z-l]++; VV[r-z]++; printf("%I64d\n",(long long)(HH.rbegin()->first) *(VV.rbegin()->first) ); } } } return 0; }
D. Clique Problem
将问题转换,每个点的x和w值可以转换成区间(x-w,x+w),然后求出不想交的区间的最大个数即答案。
求法是贪心,每次都选择右边界最小且和之前的区间不想交的区间即可。
#include<stdio.h> #include<math.h> #include<map> #include<algorithm> using namespace std; typedef pair<int,int> P; P p[200005]; int main() { int len,i,x,w; scanf("%d",&len); for(i=0;i<len;i++) { scanf("%d%d",&x,&w); p[i].first=x+w; p[i].second=x-w; } int to=-1000000005,ans=0; sort(p,p+len); for(i=0;i<len;i++) { if(p[i].second>=to) { ans++; to=p[i].first; } } printf("%d\n",ans); return 0; }
E. Data Center Drama
图论题。没A。。
先判断图是否存在欧拉回路,若不存在则补充边,(度为奇数个的点要补充)。
求出图的欧拉回路,然后顺着路径翻转编号为奇数(或偶数)的边,最后如果总边数是奇数个,就在出发点加一个自环。