Codeforces Round #601 (Div. 2)
官方题解
本场关键词
暴力、乱搞、模拟、贪心、出锅
A.Changing Volume
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | #include<bits/stdc++.h>using namespace std;
 typedef long long ll;
 int main()
 {
 ll a,b,t;
 cin>>t;
 while(t--)
 {
 cin>>a>>b;
 ll diss=(ll)abs(a-b);
 int cnt=0;
 cnt+=diss/5;
 diss%=5;
 cnt+=diss/2;
 diss%=2;
 cnt+=diss;
 cout<<cnt<<endl;
 }
 return 0;
 }
 
 | 
B.Fridge Lockers
这题出锅了,不过出题人迅速修改
思路
很明显所需最少锁链数为n,即所有冰箱连成环的情况。所有节点度数为2.
因为给定m<=n,当m=n时一定有解,否则无解。贪心即可。
AC的代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 
 | #include<bits/stdc++.h>using namespace std;
 struct node
 {
 int no,val;
 };
 node a[2005];
 bool cmp(const node &a,const node &b)
 {
 return a.val<b.val;
 }
 int main()
 {
 int t,n,m;
 cin>>t;
 while(t--)
 {
 cin>>n>>m;
 for(int i=1;i<=n;i++)
 {
 cin>>a[i].val;
 a[i].no=i;
 }
 if(m<n||n==2)
 {
 cout<<"-1"<<endl;
 }
 else
 {
 sort(a+1,a+n+1,cmp);
 vector<pair<int,int> > rec;
 
 long long ans=a[1].val+a[n].val;
 int rem=m-n;
 
 
 
 rec.push_back(make_pair(a[1].no,a[n].no));
 for(int i=2;i<=n;i++)
 {
 ans+=a[i-1].val+a[i].val;
 
 rec.push_back(make_pair(a[i-1].no,a[i].no));
 
 }
 cout<<ans+rem*(a[1].val+a[2].val)<<endl;
 for(auto i:rec)
 cout<<i.first<<" "<<i.second<<endl;
 while(rem--)
 cout<<a[1].no<<" "<<a[2].no<<endl;
 }
 }
 return 0;
 }
 
 | 
C.League of Leesins
思路
乱搞题,统计每个数字出现次数,找到起点,减去当前三元组数目,再找新产生的cnt为1的数字,一个一个输出就好。
AC代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 
 | #include<bits/stdc++.h>using namespace std;
 const int maxn=100005;
 int cnt[maxn];
 bool vis[maxn];
 vector<int> G[maxn];
 int main()
 {
 int n,a,b,c;
 cin>>n;
 list<int> QAQ;
 for(int i=2;i<n;i++)
 {
 cin>>a>>b>>c;
 cnt[a]++;
 cnt[b]++;
 cnt[c]++;
 G[a].push_back(b);
 G[a].push_back(c);
 G[b].push_back(a);
 G[b].push_back(c);
 G[c].push_back(a);
 G[c].push_back(b);
 }
 int st=0,nex;
 for(int i=1;i<=n;i++)
 if(cnt[i]==1)
 {
 st=i;
 break;
 }
 stack<int>ans;
 int n1=G[st][0],n2=G[st][1];
 if(cnt[G[st][0]]==2)
 {
 n1=G[st][0];
 n2=G[st][1];
 }
 else{
 n1=G[st][1];
 n2=G[st][0];
 }
 for(int k=1;k<=n;k++)
 {
 
 if(!vis[st])
 ans.push(st);
 vis[st]=1;
 cnt[st]--,cnt[n1]--,cnt[n2]--;
 if(k==n-2)
 {
 
 
 ans.push(n1);
 ans.push(n2);
 break;
 
 
 
 
 
 
 }
 
 if(cnt[n1]==1)
 {
 st=n1;
 for(auto i:G[n1])
 {
 for(auto j:G[n2])
 {
 if(i==j&&!vis[i])
 {
 n1=n2;
 n2=i;
 
 goto label;
 }
 }
 }
 }
 else if(cnt[n2]==1)
 {
 st=n2;
 for(auto i:G[n1])
 {
 for(auto j:G[n2])
 {
 if(i==j&&!vis[i])
 {
 n2=i;
 
 goto label;
 }
 }
 }
 }
 label:
 continue;
 }
 while(!ans.empty())
 {
 cout<<ans.top()<<' ';
 ans.pop();
 }
 return 0;
 }
 
 | 
D.Feeding Chicken
题意
r行c列矩阵网格,其中一些网格有水稻,并且在里面养了k只鸡,鸡的数量不会多于水稻的格数。现在要将这些方格分给这些鸡,要求:
①一个方格必须且只能分给一只鸡
②每只鸡至少分到一个方格
③同一只鸡分到的方格必须连成一片
④领地上最多的水稻数与最少的水稻数之差尽量小
输出标注鸡的领地的矩阵。
思路
大模拟
统计R的数量,记为$rice$
分类讨论,若$rice%k$==0,则所有鸡分的稻田的数量都是一样的都为$\dfrac{rice}{k}$块稻田
若$rice%k$不为0
那么有$rice%k$只鸡分得$\ulcorner \dfrac{rice}{k} \urcorner$块稻田
剩下$k-rice% k$只鸡分得$\llcorner \dfrac{rice}{k}  \lrcorner$ 块稻田
这个思想很重要,edu77的A题又出现了这个
这里采用从左上角开始蛇形分配土地,并将多余的空地分给最后一只鸡的分配方法。
代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 
 | #include<bits/stdc++.h>using namespace std;
 const int maxn=105;
 char mp[maxn][maxn],ans[maxn][maxn];
 char index[maxn]="!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
 inline bool fun(int no,int n,int m,int sec)
 {
 int y=(no+n-1)/n,x;
 if(y&1)
 x=no-(y-1)*n;
 else
 x=n-(no-(y-1)*n)+1;
 
 
 
 ans[x][y]=index[sec];
 if(mp[x][y]=='R')
 return 1;
 else
 return 0;
 }
 int main()
 {
 int t,r,c,k;
 cin>>t;
 while(t--)
 {
 cin>>r>>c>>k;
 int rice=0;
 for(int i=1;i<=r;i++)
 {
 for(int j=1;j<=c;j++)
 {
 cin>>mp[i][j];
 if(mp[i][j]=='R')
 rice++;
 }
 }
 bool diff;
 int sum1=0,sum2=0,st=rice/k,no=0;
 if(rice%k==0)
 {
 diff=0;
 sum1=k;
 }
 else
 {
 diff=1;
 sum1=rice%k;
 sum2=k-sum1;
 }
 for(int i=1;i<=k;i++)
 {
 int cnt=0;
 if(sum1>0)
 {
 while(cnt<st+diff)
 {
 if(fun(++no,r,c,i))
 cnt++;
 }
 sum1--;
 }
 else if(sum2>0)
 {
 while(cnt<st)
 {
 if(fun(++no,r,c,i))
 cnt++;
 }
 sum2--;
 }
 else{
 break;
 }
 while(k==i&&no<r*c)
 {
 no++;
 fun(no,r,c,i);
 }
 }
 for(int i=1;i<=r;i++)
 {
 for(int j=1;j<=c;j++)
 {
 putchar(ans[i][j]);
 }
 putchar('\n');
 }
 }
 return 0;
 }
 
 | 
E1. Send Boxes to Alice (Easy Version)
题意
洛谷页面
n个盒子,里面有0或1块巧克力,你每次可以将1块巧克力移动到相邻盒子里。保证不全为0,要求最后所有有巧克力的盒子巧克力数量不互素。求最少的移动次数。
思路
求1的总和sum,枚举每一个sum的因子(包括sum)。
将n分成一些区间,使得这一段区间的巧克力数量能被k整除。
显然当这一段区间和为k时移动代价最小,且移动到中间位置$mid$时代价最小。
这里的mid是这一段最中间的1的下标,而不是区间端点的中间值。
记录一个区间所有1的位置到临时数组rec,本轮代价$\sum\limits_{i=1}^kabs(rec_i-mid)$
记录最小代价即为答案
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 
 | #include<bits/stdc++.h>using namespace std;
 #define int long long
 const int maxn=100005,inf=0x3f3f3f3f3f3f3f3f;
 int a[maxn];
 inline int iabs(int x)
 {
 if(x>=0)
 return x;
 else
 return -x;
 }
 signed main()
 {
 int n,sum=0;
 cin>>n;
 vector<int>pos;
 for(int i=1;i<=n;i++)
 {
 cin>>a[i];
 if(a[i]==1)
 pos.push_back(i);
 sum+=a[i];
 }
 int ans=inf;
 if(sum==1)
 {
 cout<<"-1\n";
 exit(0);
 }
 for(int i=2;i<=sum;i++)
 {
 if(sum%i)
 continue;
 
 int cost=0,seg=sum/i;
 int mid=0,cnt=0;
 vector<int>rec;
 for(int j=0;j<pos.size();j++)
 {
 if(cnt<i)
 {
 rec.push_back(pos[j]);
 cnt++;
 }
 if(cnt==i)
 {
 
 int mid=rec[(i-1)>>1];
 for(int k=0;k<rec.size();k++)
 {
 cost+=iabs(rec[k]-mid);
 
 }
 rec.clear();
 cnt=0;
 }
 }
 
 ans=min(cost,ans);
 }
 cout<<ans<<"\n";
 return 0;
 }
 
 
 | 
2019年11月28日21点36分