Codeforces Round #601 (Div. 2)
Codeforces Round #601 (Div. 2)
题意:有T组数据,每组数据给两个数a和b,每次可以对a进行(-5,-2,-1,+1,+2,+5)操作中的一种,问从a转换为b最少需要多少次。
思路:贪心,对a和b的差取绝对值,先尽可能多的选操作5,再尽可能多的选操作2,最后再选操作1 .
#include<bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int total,a,b; int num[3]={5,2,1}; cin>>total; while(total--){ cin>>a>>b; long long cha=abs(a-b); int ans=0; if(cha>0){ for(int i=0;i<3;i++){ ans+=cha/num[i]; cha%=num[i]; } } cout<<ans<<endl; } return 0; }
题目数据范围被修改了,现在改为了m≤n,就很好写了
题意:给n个点,让建m条边,要求每个点至少有2个临边,建边的费用为边的两个顶点之和,问能否建出该图,如果能输出最小建造费用,否则输出-1.
思路:形成环即可,m<n和n=2时不满足要求。(这是原题目:m>n时的思路和证明:传送 )
#include<bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int total,n,m,get_num; cin>>total; while(total--){ cin>>n>>m; int ans=0; for(int i=1;i<=n;i++){ cin>>get_num; ans+=get_num; } if(n==2 || m<n){ cout<<-1<<endl; }else{ ans*=2; cout<<ans<<endl; for(int i=1;i<=n;i++){ int j=(i+1>n?1:i+1); cout<<i<<" "<<j<<endl; } } } return 0; }
题意:有一串序列,比如[1,4,2,3,5],给出它每三个数字的排序{[1,4,2],[4,2,3],[2,3,5]},现在将其打乱,大分组顺序和小分内组顺序都可能会变化如变为:
{[2,4,3],[1,2,4],[5,3,2]},现在给出被打乱后的序列,请输出它对应的任意一组可能的顺序序列
思路:开始和结尾的数只会出现一次,找到开始和结尾,然后可以确定开始的那一组,之后每两个数都能确定第三个数,用map做一下即可。
(我是unordered_map套了vector,初始化每组数中每两个数做一次key,第三个数作为值塞入对应key的vector中,后面判断总的大数组中相邻的数对应key的vector的size为2,间隔数对应key的vector的size为1)
#include<bits/stdc++.h> using namespace std; int book[100005]; vector<int>ans; unordered_map<long long,vector<int> >tree; vector<int>null_vec; struct node{ int a,b,c; }que[100005]; void solve(int a,int b,int c){ long long xiao=1LL*min(a,b); long long da=1LL*max(a,b); long long key=xiao*1000000+da; if(tree.find(key)==tree.end()){ tree[key]=null_vec; tree[key].push_back(c); }else{ tree[key].push_back(c); } } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n,a,b,c; cin>>n; memset(book,0,sizeof(book)); for(int i=1;i<=n-2;i++){ cin>>a>>b>>c; que[i].a=a;que[i].b=b;que[i].c=c; solve(a,b,c); solve(a,c,b); solve(b,c,a); book[a]++; book[b]++; book[c]++; } int start,k1,k2,end_p,gg; for(int i=1;i<=n;i++){ if(book[i]==1){ start=i; gg=i+1; break; } } for(int i=gg;i<=n;i++){ if(book[i]==1){ end_p=i; break; } } for(int i=1;i<=n;i++){ if(que[i].a==start){ k1=min(que[i].b,que[i].c); k2=max(que[i].b,que[i].c); break; }else if(que[i].b==start){ k1=min(que[i].a,que[i].c); k2=max(que[i].a,que[i].c); break; }else if(que[i].c==start){ k1=min(que[i].a,que[i].b); k2=max(que[i].a,que[i].b); break; } } ans.push_back(start); while(ans.size()+3<n){ long long key=1LL*k1*1000000+1LL*k2; int num1=tree[key][0]; int num2=tree[key][1]; int type=0; int kk1,kk2; if(num1==start){ kk1=min(k2,num2); kk2=max(k2,num2); type=1; }else if(num2==start){ kk1=min(k2,num1); kk2=max(k2,num1); type=2; } long long nk=1LL*kk1*1000000+1LL*kk2; if(tree[nk].size()==1){ swap(k1,k2); if(type==1){ kk1=min(k2,num2); kk2=max(k2,num2); }else if(type==2){ kk1=min(k2,num1); kk2=max(k2,num1); } } ans.push_back(k1); start=k1;k1=kk1;k2=kk2; } long long gk1=min(start,k1); long long gk2=max(start,k1); long long ggkey=gk1*1000000+gk2; if(tree[ggkey].size()==1){ swap(k1,k2); } for(int i=0;i<ans.size();i++){ cout<<ans[i]<<" "; } cout<<k1<<" "<<k2<<" "<<end_p<<endl; return 0; }
题意:r×c大小的农场养k只鸡,有些单位格上有米粒,现在给鸡分配空间,要求:每个鸡至少得到一个单位格,每只鸡的活动区域要4联通,自己的区域不能分开,获得米粒最多的鸡和获得米粒最少的鸡的米粒差尽可能小。
思路:S型给鸡分配场地即可,扫描得总米粒数为x,有x%k只鸡吃x/k+1粒米,有k-x%k只鸡吃x/k粒米,(我不知道整除时怎么放入总情况所以单独写了一遍整除时的,所以代码比较长(裂开))。
#include<bits/stdc++.h> using namespace std; char ditu[105][105]; char ans[105][105]; int t,r,c,k; int every_l,every_h,cont_h,cont_l; string biao="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; void solve0(){ int ct_h=0,ct_l=0; for(int i=0;i<r;i++){ if(i%2==0){ for(int j=0;j<c;j++){ if(ditu[i][j]=='R'){ ans[i][j]=biao[ct_h]; ct_h++; }else{ if(ct_l<cont_l){ ans[i][j]=biao[cont_h+ct_l]; ct_l++; }else{ if(i==0){ ans[i][j]=ans[i][j-1]; }else ans[i][j]=ans[i-1][j]; } } } }else{ for(int j=c-1;j>=0;j--){ if(ditu[i][j]=='R'){ ans[i][j]=biao[ct_h]; ct_h++; }else{ if(ct_l<cont_l){ ans[i][j]=biao[cont_h+ct_l]; ct_l++; }else{ ans[i][j]=ans[i-1][j]; } } } } } return; } void solve(){ int ct_h=0,ct_l=0,cont_mi=0; for(int i=0;i<r;i++){ if(i%2==0){ for(int j=0;j<c;j++){ if(ditu[i][j]=='R'){ cont_mi++; if(ct_h==cont_h){//is small if(cont_mi>every_l){ cont_mi=1; ct_l++; ans[i][j]=biao[cont_h+ct_l]; }else{ ans[i][j]=biao[cont_h+ct_l]; } }else{//is big if(cont_mi<every_h){ ans[i][j]=biao[ct_h]; }else{ cont_mi=0; ans[i][j]=biao[ct_h]; ct_h++; } } }else{ if(ct_h==cont_h){ if(cont_l==0) ans[i][j]=biao[cont_h-1]; else ans[i][j]=biao[cont_h+ct_l]; }else{ ans[i][j]=biao[ct_h]; } } } }else{ for(int j=c-1;j>=0;j--){ if(ditu[i][j]=='R'){ cont_mi++; if(ct_h==cont_h){//is small if(cont_mi>every_l){ cont_mi=1; ct_l++; ans[i][j]=biao[cont_h+ct_l]; }else{ ans[i][j]=biao[cont_h+ct_l]; } }else{//is big if(cont_mi<every_h){ ans[i][j]=biao[ct_h]; }else{ cont_mi=0; ans[i][j]=biao[ct_h]; ct_h++; } } }else{ if(ct_h==cont_h){ if(cont_l==0) ans[i][j]=biao[cont_h-1]; else ans[i][j]=biao[cont_h+ct_l]; }else{ ans[i][j]=biao[ct_h]; } } } } } return; } int main() { scanf("%d",&t); while(t--){ int rice=0; scanf("%d %d %d\n",&r,&c,&k); for(int i=0;i<r;i++){ scanf("%s",ditu[i]); for(int j=0;j<c;j++){ if(ditu[i][j]=='R') rice++; } } every_l=rice/k,every_h=every_l+1,cont_h=rice%k,cont_l=k-cont_h; if(every_l==0) solve0(); else solve(); for(int i=0;i<r;i++){ for(int j=0;j<c;j++){ printf("%c",ans[i][j]); } printf("\n"); } } return 0; }
E1. Send Boxes to Alice (Easy Version)
题意:一行有n个盒子,每个盒子有1个或没有巧克力,每次操作可以将第i个盒子中的一个巧克力放入第i-1或者第i+1个盒子中(盒子存在),问最少操作几次,最后所有有巧克力的盒子中的巧克力数能被k整除
思路:先分解质因数,因为是easy版本所以对于每个质因子pr,每pr个有巧克力的盒子分为一组,枚举放入每一个盒子的操作数取和的最小值即可,优化一下前缀后缀暴力就能过。
#include<bits/stdc++.h> using namespace std; vector<int>que; long long solve(int pr) { long long sum=0;//will return the value; for(int st=0;st<que.size();st+=pr){ long long ans=0; for(int i=1;i<pr;i++){ ans+=que[st+i]-que[st]; } long long l=0,r=pr-1,zuo=0,you=ans; for(int i=1;i<pr;i++){ l+=1; zuo+=l*(que[st+i]-que[st+i-1]); you-=r*(que[st+i]-que[st+i-1]); r--; ans=min(ans,zuo+you); } sum+=ans; } return sum; } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n,get_num; cin>>n; for(int i=1;i<=n;i++){ cin>>get_num; if(get_num>0){ que.push_back(i); } } if(que.size()<=1){ cout<<-1<<endl; }else{ long long ans=10000000000000000; vector<int>prime; int size_p=que.size(); prime.push_back(size_p); for(int pr=2;pr*pr<=size_p;pr++){ bool flag=false; while(size_p%pr==0){ flag=true; size_p/=pr; } if(flag)prime.push_back(pr); } if(size_p>1)prime.push_back(size_p); for(int i=0;i<prime.size();i++){ ans=min(ans,solve(prime[i])); } cout<<ans<<endl; } return 0; }
E2. Send Boxes to Alice (Hard Version)
题意:如E1,只是每个盒子中巧克力个数Ai范围改为[0,1e6]
思路:还是先分解质因数,对于一个数Ai,假设当前的质因数为pr,这个位置要满足能被k整除,有两个可能,要么是它往后面搬运pr%k石子,要么是后面往它搬运k-pr%k个石子。
对于每一个Ai满足后,因为只会对下一个位置产生影响,所以下一个位置Ai+1算上Ai产生的影响,之后又是一个新的子问题。
最后的答案为:对于每一个质因数pr,对每个位置i求min(pre[i],pr-pre[i])的和,最有取所有和种的最小值作为答案。
#include<bits/stdc++.h> using namespace std; int num[1000005]; long long solve(long long pr,int n){ long long pre=0,ans=0; for(int i=1;i<=n;i++){ pre=(pre+num[i])%pr; ans+=min(pre,pr-pre); } return ans; } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n; long long sum=0,ans=1e18; cin>>n; for(int i=1;i<=n;i++){ cin>>num[i]; sum+=num[i]; } if(sum<=1){ cout<<-1<<endl; return 0; } for(long long pr=2;pr*pr<=sum;pr++){ bool flag=false; while(sum%pr==0){ flag=true; sum/=pr; } if(flag) ans=min(solve(pr,n),ans); } if(sum>1) ans=min(solve(sum,n),ans); cout<<ans<<endl; return 0; }
题意:是一个交互题,挺有意思。在笛卡尔坐标系中有一个n个点形成的凸包,你有2种询问,第一种:询问任意三个点形成的三角形的面积。
第二种:询问任意3个点形成的2个向量的叉积的符号。要求在3n次询问内得知凸包点的顺序,从1开始逆时针输出。
思路:首先考虑叉积,2个向量a×b,若为正则b在a的左侧,若为负则b在a的右侧。第一步:以任意一对点为基准(这里采用1-2),用第二种查询得到1-2与所有不同于1-2的1-X的叉积符号,分为左右两组。第二步:对于每一侧,使用第一种查询查X、1、2,三个点形成的三角形面积的两倍,从而可以知道这一侧每个点距离1-2向量的距离,取最远的那个点记为点Y(如有多个任取其中一个即可)。第三步:再用第二种查询得到这一侧所有的1-X与1-Y的叉积符号,再根据其距离,得到这一侧的所有点的顺序。另一侧同理。
#include<bits/stdc++.h> using namespace std; double query1(int i,int j,int k){ double answer; cout<<1<<" "<<i<<" "<<j<<" "<<k<<endl; cin>>answer; return answer; } int query2(int i,int j,int k){ int answer; cout<<2<<" "<<i<<" "<<j<<" "<<k<<endl; cin>>answer; return answer; } struct node{ int loc; double dis; }now; vector<node>loc_left,loc_right; vector<int>ans; int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int n; cin>>n; for(int i=3;i<=n;i++){ if(query2(1,2,i)==1){ now.loc=i; loc_left.push_back(now); }else{ now.loc=i; loc_right.push_back(now); } } for(int i=0;i<loc_left.size();i++){ loc_left[i].dis=query1(1,2,loc_left[i].loc); } for(int i=0;i<loc_right.size();i++){ loc_right[i].dis=query1(1,2,loc_right[i].loc); } sort(loc_left.begin(),loc_left.end(),[](const node &a,const node &b){return a.dis>b.dis;}); sort(loc_right.begin(),loc_right.end(),[](const node &a,const node &b){return a.dis>b.dis;}); ans.push_back(0);ans.push_back(1); vector<int>loc_right_l,loc_right_r; if(!loc_right.empty()){ int right_max=loc_right[0].loc; for(int i=0;i<loc_right.size();i++){ if(right_max==loc_right[i].loc) continue; if(query2(1,right_max,loc_right[i].loc)==1){ loc_right_l.push_back(loc_right[i].loc); }else{ loc_right_r.push_back(loc_right[i].loc); } } if(!loc_right_r.empty()){ for(int i=loc_right_r.size()-1;i>=0;i--){ ans.push_back(loc_right_r[i]); } } ans.push_back(right_max); for(int i=0;i<loc_right_l.size();i++){ ans.push_back(loc_right_l[i]); } } ans.push_back(2); vector<int>loc_left_l,loc_left_r; if(!loc_left.empty()){ int left_max=loc_left[0].loc; for(int i=0;i<loc_left.size();i++){ if(left_max==loc_left[i].loc) continue; if(query2(1,left_max,loc_left[i].loc)==1){ loc_left_l.push_back(loc_left[i].loc); }else{ loc_left_r.push_back(loc_left[i].loc); } } if(!loc_left_r.empty()){ for(int i=loc_left_r.size()-1;i>=0;i--){ ans.push_back(loc_left_r[i]); } } ans.push_back(left_max); for(int i=0;i<loc_left_l.size();i++){ ans.push_back(loc_left_l[i]); } } for(int i=0;i<ans.size();i++){ cout<<ans[i]<<" "; } cout<<endl; return 0; }
这期题还是蛮有意思的~( 逃ε=ε=ε=┏(゜ロ゜;)┛