4-25ACM训练题解(gym 102392)
D Cycle string Gym - 102392D by ltr
我们可以发现,当所有字母出现次数都<=n时,我们只要把所有字母排序就一定可以满足条件,因为不可能有两个首字母相同的子串他们首字母出现的次数也相同。
当有一个字母出现次数>n时,我们分类讨论,若出现次数为2*n或2*n-1,显然无解,当出现次数为2*n-2时,若另外两个字母不同,则有解,我们可以排成A……ABA……AC的形式,若相同,则无解。
当出现次数<=2*n-3时,我们排成A……ABA……CCDD……E的形式即为答案。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #define N 1000005 10 using namespace std; 11 char B[N]; 12 int cnt[30]; 13 int ans[N],n; 14 int js; 15 int main() 16 { 17 scanf("%s",B+1); 18 n=strlen(B+1); 19 for(int i=1;i<=n;i++) 20 { 21 cnt[B[i]-'a'+1]++; 22 if(cnt[B[i]-'a'+1]==1) js++; 23 } 24 int mx=0,bj=-1;; 25 for(int i=1;i<=26;i++) 26 { 27 mx=max(mx,cnt[i]); 28 if(mx==cnt[i]) bj=i; 29 } 30 if(mx<=n/2) 31 { 32 printf("YES\n"); 33 int zz=0; 34 for(int i=1;i<=26;i++) 35 { 36 while(cnt[i]) 37 { 38 zz++; 39 ans[zz]=i; 40 cnt[i]--; 41 } 42 } 43 for(int i=1;i<=n;i++) 44 { 45 printf("%c",(char)ans[i]+'a'-1); 46 } 47 } 48 else 49 { 50 if(mx==n||mx==n-1) 51 { 52 printf("NO\n"); 53 } 54 else if(mx==n-2) 55 { 56 if(js==2) 57 { 58 printf("NO\n"); 59 } 60 else 61 { 62 for(int i=1;i<=26;i++) 63 { 64 if(cnt[i]!=mx&&cnt[i]) 65 { 66 ans[n/2]=i; 67 cnt[i]--; 68 break; 69 } 70 } 71 for(int i=1;i<=26;i++) 72 { 73 if(cnt[i]!=mx&&cnt[i]) 74 { 75 ans[n]=i; 76 cnt[i]--; 77 break; 78 } 79 } 80 for(int i=1;i<=n;i++) 81 { 82 if(i!=n&&i!=n/2) ans[i]=bj; 83 } 84 printf("YES\n"); 85 for(int i=1;i<=n;i++) 86 { 87 printf("%c",(char)ans[i]+'a'-1); 88 } 89 } 90 } 91 else 92 { 93 printf("YES\n"); 94 for(int i=1;i<=26;i++) 95 { 96 if(cnt[i]!=mx&&cnt[i]) 97 { 98 ans[n/2]=i; 99 cnt[i]--; 100 break; 101 } 102 } 103 for(int i=1;i<n/2;i++) 104 { 105 ans[i]=bj; 106 } 107 for(int i=n/2+1;i<=mx+1;i++) 108 { 109 ans[i]=bj; 110 } 111 112 cnt[bj]=0; 113 int now=0; 114 for(int i=mx+2;i<=n;i++) 115 { 116 while(!cnt[now]) now++; 117 ans[i]=now; 118 cnt[now]--; 119 } 120 121 for(int i=1;i<=n;i++) 122 { 123 printf("%c",(char)ans[i]+'a'-1); 124 } 125 } 126 } 127 return 0; 128 }
E Life transfer Gym - 102392E by ltr
我们可以先贪心得到一个结论,如果我们将人的年龄从小到大排列,那么一定是较小的坐车,较大的开车,中间一部分人骑车,这样一定不劣,原因显然。那么,我们可以去枚举有多少人坐车,当我们知道有多少人坐车,则开车和骑车的人数也都知道了,这里主要靠一些桶来维护,细节很多。
首先,我们要保证做摩托车的人他们在被分配d的年龄时都到达了年龄限制。
其次,我们我们要保证开车的人在被分配d的年龄的时候达到了年龄限制。
还有就是从小到大枚举的坐车的人和从大到小枚举的开车的人不会交叉重复。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #define N 100005 10 using namespace std; 11 int n,K; 12 long long lc,pc,lm,pm,t,d; 13 int A[N]; 14 long long ans=1e18; 15 long long sm[N],to[N],sum; 16 int l1,l2; 17 int main() 18 { 19 scanf("%d%d",&n,&K); 20 scanf("%lld%lld%lld%lld",&lc,&pc,&lm,&pm); 21 scanf("%lld%lld",&t,&d); 22 for(int i=1;i<=n;i++)scanf("%d",&A[i]); 23 sort(A+1,A+n+1); 24 25 for(int i=1;i<=n;i++) 26 { 27 if(A[i]<lm) 28 { 29 l1=i; 30 } 31 else break; 32 } 33 for(int i=l1;i;i--) 34 { 35 sm[i]=sm[i+1]+lm-A[i]; 36 to[i]=A[i]; 37 } 38 for(int i=l1+1;i<=n;i++) 39 { 40 if(A[i]-d>=lm) to[i]=A[i]-d,sum+=d; 41 else to[i]=lm,sum+=A[i]-lm; 42 } 43 int zz1=n+1; 44 45 if(sm[1]<=sum&&A[1]+d>=lm) 46 { 47 ans=1ll*sm[1]*t+1ll*n*pm; 48 } 49 if(K!=1) 50 { 51 long long tmp=0; 52 for(int i=1;i<=n;i++) 53 { 54 if(A[i]>d) sum+=d; 55 else sum+=A[i]-1; 56 if((i+(K-2))/(K-1)>n-zz1+1) 57 { 58 zz1--; 59 if(A[zz1]<lc) 60 { 61 tmp+=lc-A[zz1]; 62 sum-=A[zz1]-to[zz1]; 63 } 64 else if(to[zz1]<lc) 65 { 66 sum-=lc-to[zz1]; 67 } 68 if(A[zz1]+d<lc) 69 { 70 break; 71 } 72 } 73 74 if(A[i+1]+d<lm&&zz1>i+1) continue; 75 if(sm[i+1]-sm[zz1]+tmp<=sum&&zz1>i) 76 { 77 ans=min(ans,1ll*t*(sm[i+1]-sm[zz1]+tmp)+1ll*(n-zz1+1)*pc+1ll*(zz1-i-1)*pm); 78 } 79 } 80 } 81 if(ans==1e18) printf("-1\n"); 82 else printf("%lld\n",ans); 83 return 0; 84 }
F Game on a tree Gym - 102392F by myl
博弈论问题
思考Bob获胜的条件,即Alice每走一步,Bob都有合法的一步可走
通过树形dp,对树进行匹配,如果得到完美匹配则Bob胜利,否则Alice胜利
1 #include<cstdio> 2 3 int a,b,c,d,e,f,g,m,n; 4 int xa[500000]={0},xb[500000]={0}; 5 int wa[500000]={0},wb[500000]={0}; 6 7 int df(int j) 8 { 9 int k,r,s; 10 k=0; 11 xa[j]=1; 12 r=xb[j]; 13 s=wa[r]; 14 while(r!=0) 15 { 16 if(xa[s]==0) k+=df(s); 17 r=wb[r]; 18 s=wa[r]; 19 } 20 k--; 21 if(k<0) k=1; 22 return k; 23 } 24 25 int main() 26 { 27 int i,j,k; 28 scanf("%d",&n); 29 for(i=1;i<n;i++) 30 { 31 scanf("%d%d",&a,&b); 32 wa[2*i-1]=b; 33 wb[2*i-1]=xb[a]; 34 xb[a]=2*i-1; 35 wa[2*i]=a; 36 wb[2*i]=xb[b]; 37 xb[b]=2*i; 38 } 39 if((n%2==0)&&(df(1)==0)) printf("Bob\n"); 40 else printf("Alice\n"); 41 }
G projection Gym - 102392G by ltr
贪心,为了方便,我们可以把他一层一层的进行处理。
求最大的时候很简单,所有交叉点都放上方块
求最小的时候稍有麻烦,我们设长(y)上共有cnt[0]个阴影,宽(z)上有cnt[1]个阴影,则为了满足字典序最小,我们要分类讨论。
cnt[0]>=cnt[1],则长上前cnt[0]-cnt[1]+1个阴影都与宽上第一个阴影对应,剩下的点依次与宽上第2个,第3个……对应。
cnt[1]>cnt[0],则宽上前cnt[1]-cnt[0]+1个阴影都与长上第一个阴影对应,剩下的点依次与长上第2个,第3个……对应。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #define N 105 10 using namespace std; 11 int n,m,h; 12 struct no{ 13 int x,y,z; 14 }node[N*N*N]; 15 bool cmp(const no &a,const no &b) 16 { 17 if(a.x==b.x&&a.y==b.y)return a.z<b.z; 18 if(a.x==b.x)return a.y<b.y; 19 return a.x<b.x; 20 } 21 char B[N]; 22 int ma1[N][N],ma2[N][N]; 23 int q[2][N]; 24 int zz=0; 25 int main() 26 { 27 // freopen("test.in","r",stdin); 28 // freopen("1.out","w",stdout); 29 scanf("%d%d%d",&n,&m,&h); 30 for(int i=1;i<=n;i++) 31 { 32 scanf("%s",B+1); 33 for(int j=1;j<=m;j++) 34 { 35 ma1[i][j]=(B[j]=='1'); 36 } 37 } 38 for(int i=1;i<=n;i++) 39 { 40 scanf("%s",B+1); 41 for(int j=1;j<=h;j++) 42 { 43 ma2[i][j]=(B[j]=='1'); 44 } 45 } 46 bool yx=1; 47 for(int i=1;i<=n;i++) 48 { 49 q[1][0]=q[0][0]=0; 50 for(int j=1;j<=m;j++) 51 { 52 if(ma1[i][j]) 53 { 54 q[0][0]++; 55 q[0][q[0][0]]=j; 56 } 57 } 58 for(int j=1;j<=h;j++) 59 { 60 if(ma2[i][j]) 61 { 62 q[1][0]++; 63 q[1][q[1][0]]=j; 64 } 65 } 66 if(!q[1][0]&&q[0][0]) yx=0; 67 if(q[1][0]&&!q[0][0]) yx=0; 68 for(int j=1;j<=q[0][0];j++) 69 { 70 for(int k=1;k<=q[1][0];k++) 71 { 72 zz++; 73 node[zz].x=i,node[zz].y=q[0][j],node[zz].z=q[1][k]; 74 } 75 } 76 } 77 if(!yx) 78 { 79 printf("-1\n"); 80 return 0; 81 } 82 sort(node+1,node+zz+1,cmp); 83 printf("%d\n",zz); 84 for(int i=1;i<=zz;i++) 85 { 86 printf("%d %d %d\n",node[i].x-1,node[i].y-1,node[i].z-1); 87 } 88 zz=0; 89 for(int i=1;i<=n;i++) 90 { 91 q[1][0]=q[0][0]=0; 92 for(int j=1;j<=m;j++) 93 { 94 if(ma1[i][j]) 95 { 96 q[0][0]++; 97 q[0][q[0][0]]=j; 98 } 99 } 100 for(int j=1;j<=h;j++) 101 { 102 if(ma2[i][j]) 103 { 104 q[1][0]++; 105 q[1][q[1][0]]=j; 106 } 107 } 108 if(q[0][0]<=q[1][0]) 109 { 110 for(int j=1;j<=q[1][0]-q[0][0];j++) 111 { 112 zz++; 113 node[zz].x=i; 114 node[zz].y=q[0][1]; 115 node[zz].z=q[1][j]; 116 } 117 for(int j=1;j<=q[0][0];j++) 118 { 119 zz++; 120 node[zz].x=i; 121 node[zz].y=q[0][j]; 122 node[zz].z=q[1][j+q[1][0]-q[0][0]]; 123 } 124 } 125 else 126 { 127 for(int j=1;j<=q[0][0]-q[1][0];j++) 128 { 129 zz++; 130 node[zz].x=i; 131 node[zz].y=q[0][j]; 132 node[zz].z=q[1][1]; 133 } 134 for(int j=1;j<=q[1][0];j++) 135 { 136 zz++; 137 node[zz].x=i; 138 node[zz].y=q[0][q[0][0]-q[1][0]+j]; 139 node[zz].z=q[1][j]; 140 } 141 } 142 } 143 printf("%d\n",zz); 144 sort(node+1,node+zz+1,cmp); 145 for(int i=1;i<=zz;i++) 146 { 147 printf("%d %d %d\n",node[i].x-1,node[i].y-1,node[i].z-1); 148 } 149 return 0; 150 }
I Absolute Game Gym - 102392I by myl
博弈论
由于n只有1000,直接暴力枚举所有情况,找到所以最大的最小值,即为最终的答案
1 #include<cstdio> 2 3 int a,b,c,d,e,f,g,m,n; 4 int xa[200000]={0},xb[200000]={0}; 5 6 void ma(int &j,int k) 7 { 8 if(j<k) j=k; 9 } 10 11 void mi(int &j,int k) 12 { 13 if(j>k) j=k; 14 } 15 16 int zh(int j) 17 { 18 if(j<0) return -j; 19 return j; 20 } 21 22 int main() 23 { 24 int i,j,k; 25 scanf("%d",&n); 26 for(i=1;i<=n;i++) 27 { 28 scanf("%d",&xa[i]); 29 } 30 for(i=1;i<=n;i++) 31 { 32 scanf("%d",&xb[i]); 33 } 34 a=0; 35 for(i=1;i<=n;i++) 36 { 37 b=zh(xa[i]-xb[n]); 38 for(j=1;j<n;j++) 39 { 40 mi(b,zh(xa[i]-xb[j])); 41 } 42 ma(a,b); 43 } 44 printf("%d\n",a); 45 }
J Graph and Cycles Gym - 102392J by wxh
对于这道题,单独考虑每个点,在任何一个环中必然是选择两个值连续的边。
那么我们对每个点的边排序,加上每两个边的大值就可以了
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct data { 4 int END, v, next; 5 }v[997007]; 6 int first[1000], p; 7 void add(int a, int b, int c) { 8 v[p].END = b; 9 v[p].v = c; 10 v[p].next = first[a]; 11 first[a] = p++; 12 } 13 vector<int> vc; 14 int main() { 15 int n, m; 16 memset (first, -1, sizeof(first)); 17 scanf ("%d", &n); 18 m = n * (n - 1) / 2; 19 int a, b, c; 20 for (int i = 1; i <= m; i++) { 21 scanf ("%d%d%d", &a, &b, &c); 22 add(a, b, c); 23 add(b, a, c); 24 } 25 long long ans = 0; 26 for (int i = 1; i <= n; i++) { 27 vc.clear(); 28 for (int j = first[i]; j != -1; j = v[j].next) { 29 vc.push_back(v[j].v); 30 } 31 sort(vc.begin(), vc.end(), greater<int>()); 32 for (int j = 0; j < vc.size(); j += 2) { 33 ans += vc[j]; 34 } 35 } 36 printf ("%lld\n", ans); 37 }