2020牛客暑期多校训练营(第三场)题解
A - Clam and Fish(贪心)
思路:
贪心,首先有鱼一定钓鱼,将没有鱼的天数单独拉出来考虑
首先从无鱼的第一天开始枚举,若当前天数有蛤蜊就收集,若啥都没,则用手头的蛤蜊换鱼
同时注意当当前手头的蛤蜊数等于剩余的天数,则剩余天数每天都可以换一条鱼
代码:
#include<iostream> #include<algorithm> using namespace std; const int maxn=2e6+10; char s[maxn]; int main() { int t,n; scanf("%d",&t); while(t--){ scanf("%d%s",&n,s);; int ans=0,num=0,x=0; for(int i=0;i<n;i++) if(s[i]=='0'||s[i]=='1') num++; for(int i=0;i<n;i++){ num-=(s[i]=='0'||s[i]=='1'); if(s[i]=='0'){ if(x){ ans++; x--; } } else if(s[i]=='1'){ if(x+1>num&&x){ x--; ans++; } else x++; } else ans++; } cout<<ans<<endl; } return 0; }
B - Classical String Problem(模拟)
思路:
其实操作一只是在改变字符串循环的开头而已,我们只要记录头指针即可
代码:
#include"bits/stdc++.h" using namespace std; char s[2000005]; int n; int q; int p; int main() { int T; char ss[4]; scanf("%s",s); n=strlen(s); cin>>T; while(T--) { scanf("%s",ss);scanf("%d",&p); if(ss[0]=='M') { q+=p; q%=n; if(q<0)q+=n; } else { int t; printf("%c\n",s[(p+q-1)%n]); } } return 0; }
C - Operation Love(几何)
思路:
我们找三条比较有特征的边,大拇指外侧,底侧,小指外侧长度分别为$6,9,8$
用叉积判断点是顺时针还是逆时针给出的,然后看顺时针/逆时针方向上这三条边顺序,即可判断左右手
代码:
#include<cstdio> #include<iostream> #include<cmath> using namespace std; const int maxn=30; double a[maxn],b[maxn]; double d[maxn]; double jud(int s,int t){ return sqrt((a[s]-a[t])*(a[s]-a[t])+(b[s]-b[t])*(b[s]-b[t])); } int S(int p1,int p2,int p3){ // 1 right 2 left double ans=(a[p1]-a[p3])*(b[p2]-b[p3])-(b[p1]-b[p3])*(a[p2]-a[p3]); if(ans>0) return 1; else return 0; } int main(){ int T; cin>>T; while(T--){ for(int i=1;i<=20;i++){ scanf("%lf%lf",&a[i],&b[i]); } int p1,p2,p3; int get8=0,get9=0; for(int i=1;i<=19;i++){ d[i]=jud(i,i+1); }d[20]=jud(20,1); d[21]=d[1]; a[21]=a[1]; b[21]=b[1];a[22]=a[2]; b[22]=b[2]; for(int i=1;i<=20;i++){ if(abs(d[i]-9)<=0.01 && abs(d[i+1]-8)<=0.01){ p1=i;p2=i+1;p3=i+2; if(S(p1,p2,p3)) cout<<"right"<<endl; else cout<<"left"<<endl; } if(abs(d[i]-8)<=0.01 && abs(d[i+1]-9)<=0.01){ p3=i;p2=i+1;p1=i+2; if(S(p1,p2,p3)) cout<<"right"<<endl; else cout<<"left"<<endl; } } } }
D - Points Construction Problem(构造)
代码:
#include"bits/stdc++.h" using namespace std; int a[60]; int b[60]; int dx,dy; int px[60],py[60]; int m[7][7]={1, 2, 9, 10, 25, 26, 49, 4, 3, 8, 11, 24, 27, 48, 5, 6, 7, 12, 23, 28, 47, 16, 15, 14, 13, 22, 29, 46, 17, 18, 19, 20, 21, 30, 45, 36, 35, 34, 33, 32, 31, 44, 37, 38, 39, 40, 41, 42, 43 }; void out(int t) { for(int i=1;i<=t;i++)printf("%d %d\n",px[i]+dx,py[i]+dy); dx+=50; } void out2(int t,int m) { if(m==b[t]) { out(t); return; } if(t>=4&&m-2==b[t-1]) { out(t-1); printf("%d %d\n",-1+dx-50,0+dy); return; } for(int i=1;i<=t;i++) { if(b[t-i]<=m-b[i]&&m-b[i]<=a[t-i]) { out(i); out2(t-i,m-b[i]); return; } } } int main() { a[1]=b[1]=4; for(int i=2;i<55;i++) { a[i]=a[i-1]+4; } int k=0,t=0; for(int i=2;i<55;i++) { if(t<k/2)b[i]=b[i-1],t++; else { b[i]=b[i-1]+2; k=k+1; t=0; }//cout<<i<<":"<<b[i]<<endl;//<<" "<<k<<endl; } //for(int i=0;i<55;i++)cout<<i<<":"<<b[i]<<endl; for(int i=0;i<7;i++)for(int j=0;j<7;j++) { px[m[i][j]]=i; py[m[i][j]]=j; }//for(int i=1;i<50;i++)cout<<px[i]<<" "<<py[i]<<endl; //for(int i=1;i<51;i++)cout<<i<<":"<<b[i]<<"-"<<a[i]<<endl; px[50]=7;py[50]=3; // // // // // //out2(11,16); int T; cin>>T; while(T--) { int n,m; scanf("%d%d",&n,&m); if(m%2)printf("No\n"); else if(b[n]<=m&&m<=a[n]) { printf("Yes\n"); out2(n,m); } else { printf("No\n"); } } return 0; }
E - Two Matchings(DP)
代码:
#include"bits/stdc++.h" #define ll long long using namespace std; int a[200015]; ll dp[200035]; int main() { int T; cin>>T; while(T--) { int n; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",a+i); sort(a,a+n); for(int i=7;i<n;i+=2) { dp[i-4]=max(dp[i-4],dp[i-6]); dp[i]=dp[i-4]+a[i-3]-a[i-4]; } ll ans=0; for(int i=1;i<n;i+=2)ans=max(ans,dp[i]); ans=(ll)2*(a[n-1]-a[0])-2*ans; ; printf("%lld\n",ans); for(int i=0;i<n+10;i++)dp[i]=0; } return 0; }
F - Fraction Construction Problem(拓展欧几里得)
代码:
#include"bits/stdc++.h" #define ll long long using namespace std; void gcd(int a,int b,int *x,int *y) { if(b==0) { *x=1; *y=0; return; } //x*a-y*b=1 int k=a/b; int c=a%b; //a=k*b+c int x0,y0; gcd(b,c,&x0,&y0); //x=-y0,y=-y0k-x0 ll xx=-y0,yy=-y0*(ll)k-x0; //xx+b;yy+a ll kk=y0/b; xx=xx+kk*b; yy=yy+kk*a; if(xx<0)xx=xx+b,yy=yy+a; *x=(int)xx; *y=(int)yy; } int isprime(int a) { int p=min((int)sqrt((double)a)+2,a-1); for(int i=2;i<=p;i++) { if(a%i==0)return i; } return 0; } int main() {//cout<<37*37-3*444; int T; cin>>T; while(T--) { int a,b; scanf("%d%d",&a,&b); int p=isprime(b); if(p==0) { if(b==1)printf("-1 -1 -1 -1\n"); else { if(a%b==0) { printf("%d %d %d %d\n",a/b+1,1,1,1); } else printf("-1 -1 -1 -1\n"); } } else { if(a%p==0) { printf("%d %d %d %d\n",a/p+1,b/p,1,b/p); } // else { int q=b/p; while(1) { if(q%p==0)q/=p; else break; } p=b/q; if(q==1) { printf("-1 -1 -1 -1\n"); continue; } int x,y; gcd(q,p,&x,&y); printf("%lld %d %lld %d\n",x*(ll)a,p,y*(ll)a,q); } } } return 0; }
G - Operating on a Graph(并查集+启发式合并)
思路:
我们用并查集去维护每个点到底属于哪个集合
但是本题比较棘手的地方在于合并,但是我们可以发现这样的一个规律,对于每个点至多只会进行一次把相邻的点变为与自己同集合的操作
所有,我们对于每个集合开一个链表用于维护本集合中的边缘点(未进行过操作的点)
在进行吞并操作的时候,一个集合的边缘点就变成了与其相邻集合的所有边缘点,所以这里会有一个合并所有集合边缘点的操作
这个合并操作我们使用启发式合并,每次都将小的集合加入大的集合中,能有有效的降低时间复杂度
代码:
#include<iostream> #include<algorithm> #include<vector> using namespace std; const int maxn=8e5+10; vector<int> a[maxn]; int fa[maxn]; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } int main() { int t,n,m,q,x,u,v; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=0;i<n;i++){ fa[i]=i; a[i].clear(); } for(int i=1;i<=m;i++){ scanf("%d%d",&u,&v); a[u].push_back(v); a[v].push_back(u); } scanf("%d",&q); while(q--){ scanf("%d",&x); if(x!=fa[x]) continue; vector<int> tmp; for(int i=0;i<a[x].size();i++){ int v=a[x][i]; int rt=find(v); if(x!=rt){ if(tmp.size()<a[rt].size()) swap(a[rt],tmp); for(int j=0;j<a[rt].size();j++) tmp.push_back(a[rt][j]); a[rt].clear(); fa[rt]=x; } } swap(tmp,a[x]); } for(int i=0;i<n;i++) printf("%d ",find(i)); printf("\n"); } return 0; }
L - Problem L is the Only Lovely Problem(模拟)
思路:
直接进行比对即可
代码:
#include<iostream> #include<algorithm> #include<vector> #include<map> #include<set> using namespace std; typedef long long ll; int main() { string s; cin>>s; int flag=0; string tmp="lovely"; for(int i=0;i<tmp.size();i++){ if(tmp[i]==s[i]||(s[i]-'A'+'a')==tmp[i]){ continue; } flag=1; break; } if(flag) cout<<"ugly"; else cout<<"lovely"; return 0; }