codeforces Educational Round 65 ABCDF题解
昨晚刷的cf,真的是手速场啊。
A题。
大水题,看看字符串中第一个8后面(包括自己)是不是大于或等于11就行了。
1 // Cease to struggle and you cease to live 2 #include <iostream> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <stack> 12 using namespace std; 13 typedef long long ll; 14 int main() { 15 int T;scanf("%d",&T); 16 for(int t=1;t<=T;++t){ 17 int n;scanf("%d",&n); 18 string s;cin>>s; 19 int st=-1; 20 for(int i=0;i<n;++i){ 21 if(s[i]=='8'){ 22 st=i; 23 break; 24 } 25 } 26 if(st==-1 || n-st<11) puts("NO"); 27 else puts("YES"); 28 } 29 return 0; 30 }
B题。
emm第一次打交互题,卡了挺久的。。。。。交互题的姿势题面已经给了。然后看看那6个数字可以看出来,只要给你一个数,你肯定知道是哪两个数的乘积,所以询问1,2的乘积可以确定1,2是哪两个数(顺序还未确定),再询问2,3的乘积(顺序未定)。那样就可以知道1,2,3的顺序了,4,5,6同理
1 // Cease to struggle and you cease to live 2 #include <iostream> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <stack> 12 using namespace std; 13 typedef long long ll; 14 int ans[10]; 15 int val[10]; 16 map<int,int> mp; 17 map<int,int> in; 18 int main() { 19 int a12,a23,a45,a56; 20 val[1]=4; 21 val[2]=8; 22 val[3]=15; 23 val[4]=16; 24 val[5]=23; 25 val[6]=42; 26 in[4]=1; 27 in[8]=1; 28 in[15]=1; 29 in[16]=1; 30 in[23]=1; 31 in[42]=1; 32 cout<<"? 1 2"<<endl; 33 fflush(stdout); 34 cin>>a12; 35 36 cout<<"? 2 3"<<endl; 37 fflush(stdout); 38 cin>>a23; 39 40 cout<<"? 4 5"<<endl; 41 fflush(stdout); 42 cin>>a45; 43 44 cout<<"? 5 6"<<endl; 45 fflush(stdout); 46 cin>>a56; 47 48 int t1,t2; 49 for(int i=1;i<=6;++i){ 50 if(a12%val[i]) continue; 51 if(in[a12/val[i]]==0) continue; 52 mp[val[i]]=1; 53 mp[a12/val[i]]=1; 54 t1=val[i],t2=a12/val[i]; 55 break; 56 } 57 for(int i=1;i<=6;++i){ 58 if(a23%val[i]) continue; 59 if(in[a23/val[i]]==0) continue; 60 int u=a23/val[i],v=val[i]; 61 if(mp[u]==1){ 62 ans[2]=u; 63 ans[3]=v; 64 if(t1==u) ans[1]=t2; 65 else ans[1]=t1; 66 } 67 else { 68 ans[2]=v; 69 ans[3]=u; 70 if(t1==v) ans[1]=t2; 71 else ans[1]=t1; 72 } 73 break; 74 } 75 for(int i=1;i<=6;++i) mp[val[i]]=0; 76 77 for(int i=1;i<=6;++i){ 78 if(a45%val[i]) continue; 79 if(in[a45/val[i]]==0) continue; 80 mp[val[i]]=1; 81 mp[a45/val[i]]=1; 82 t1=val[i],t2=a45/val[i]; 83 break; 84 } 85 for(int i=1;i<=6;++i){ 86 if(a56%val[i]) continue; 87 if(in[a56/val[i]]==0) continue; 88 int u=a56/val[i],v=val[i]; 89 if(mp[u]==1){ 90 ans[5]=u; 91 ans[6]=v; 92 if(t1==u) ans[4]=t2; 93 else ans[4]=t1; 94 } 95 else { 96 ans[5]=v; 97 ans[6]=u; 98 if(t1==v) ans[4]=t2; 99 else ans[4]=t1; 100 } 101 break; 102 } 103 104 105 cout<<"! "; 106 fflush(stdout); 107 for(int i=1;i<6;++i){ 108 cout<<ans[i]<<" "; 109 fflush(stdout); 110 } 111 cout<<ans[6]<<endl; 112 fflush(stdout); 113 return 0; 114 }
C题。
就是并查集的裸题,求这个集合的大小
1 // Cease to struggle and you cease to live 2 #include <iostream> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <stack> 12 using namespace std; 13 typedef long long ll; 14 const int N=5e5+9; 15 int siz[N],f[N]; 16 int tem[N]; 17 int find(int x){ 18 if(f[x]==x) return x; 19 return f[x]=find(f[x]); 20 } 21 int main() { 22 int n,m;scanf("%d%d",&n,&m); 23 for(int i=1;i<=n;++i) f[i]=i,siz[i]=1; 24 for(int i=1;i<=m;++i){ 25 int t;scanf("%d",&t); 26 for(int j=1;j<=t;++j) scanf("%d",&tem[j]); 27 sort(tem+1,tem+1+t); 28 int fa=tem[1]; 29 for(int j=2;j<=t;++j){ 30 int u=find(fa),v=find(tem[j]); 31 if(u!=v){ 32 f[v]=u; 33 siz[u]+=siz[v]; 34 } 35 } 36 } 37 for(int i=1;i<=n;++i){ 38 int u=find(i); 39 printf("%d ",siz[u]); 40 } 41 return 0; 42 }
D题。
就是一个贪心题。因为我要让两者的最大值最小,那么就是不可以搞极端。从左到右枚举,记录红色和蓝色现有的“(“。出现“("时,肯定是把它往现有"("少的的那一方方。如果是出现")",那肯定是先把它往"("多的那一放。
1 // Cease to struggle and you cease to live 2 #include <iostream> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <stack> 12 using namespace std; 13 typedef long long ll; 14 int main() { 15 int n; 16 scanf("%d",&n); 17 string s; 18 cin>>s; 19 int a=0,b=0; 20 for(int i=0;i<n;++i){ 21 if(s[i]=='('){ 22 if(a>b){ 23 printf("0"); 24 ++b; 25 } 26 else { 27 printf("1"); 28 ++a; 29 } 30 } 31 else{ 32 if(a>b){ 33 printf("1"); 34 --a; 35 } 36 else{ 37 printf("0"); 38 --b; 39 } 40 } 41 } 42 return 0; 43 }
F题。
F这种就是让你求1<=l<=r<=n的l到r区间某某和的这种题,都是一个套路。1、我要做的不是枚举l和r(n²妥妥的T),我要做的是求每一个数的贡献。2、每一个数的贡献虽然看上去是和l和r有关,但是最后推出来的式子是和l和r无关的。
好,我们来看看这题。我们来看a[i]对答案的贡献,就是如果我一个l到r的区间里面,有num个比a[i]少的数,那么答案就加a[i]*num,也就是说一个比a[i]小的数都会增加a[i]对答案的贡献。那么假如在i的左边有一个a[j]<a[i],那么这个a[j]会使得a[i]对答案的贡献增多几个a[i]呢?答案是j*(n-i+1),因为有这么多个lr区间包含j和i。那么怎么统计呢?我们从左往右枚举,枚举到a[i],处理i左边的数对a[i]的对答案的贡献。那么也就是求∑j*(n-i+1)*a[i] (其中j<i,a[j]<a[i])。这个东西就用树状数组维护,注意a[i]1e9,所以要离散化。
然后再从右往左枚举,求出a[i]右边的数增加的 a[i]的对答案的贡献。
最后注意取模。乘法和取模优先级相同,原则上乘一次再模一次(因为这个WA35了。。。)
1 // Cease to struggle and you cease to live 2 #include <iostream> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <stack> 12 using namespace std; 13 typedef long long ll; 14 const ll modd=1e9+7; 15 const int N=5e5+7; 16 int n; 17 ll a[N]; 18 ll b[N]; 19 ll tr[N]; 20 void add(int x,ll v){ 21 for(;x<=n;x+=x&-x) tr[x]=(tr[x]+v)%modd; 22 } 23 ll sum(int x){ 24 ll res=0; 25 for(;x;x-=x&-x) res=(res+tr[x])%modd; 26 return res; 27 } 28 int main() { 29 scanf("%d",&n); 30 ll ans=0; 31 for(int i=1;i<=n;++i) scanf("%lld",&a[i]),b[i]=a[i]; 32 sort(b+1,b+1+n); 33 for(int i=1;i<=n;++i){ 34 ans=(ans+a[i]*(((ll)i*(ll)(n-i+1))%modd))%modd; 35 int p=lower_bound(b+1,b+1+n,a[i])-b; 36 ans=(ans+a[i]*(sum(p-1)*(n-i+1)%modd))%modd; 37 add(p,i); 38 } 39 memset(tr,0,sizeof(tr)); 40 for(int i=n;i>=1;--i){ 41 int p=lower_bound(b+1,b+1+n,a[i])-b; 42 ans=(ans+a[i]*(sum(p-1)*i%modd))%modd; 43 add(p,n-i+1); 44 } 45 printf("%lld",ans%modd); 46 return 0; 47 }
感觉这几题除了B题,代码量都很少。