cf2
1.Codeforces Global Round 15 B. Running for Gold
大意:有五项比赛,给出n个运动员在这五项比赛中的排名,运动员A战胜B当且仅当在这五项比赛中至少有三项成绩A在B之上,夺冠必须战胜其他所有人,输出夺冠的运动员,若无人夺冠,输出-1。
题解:设置一个可能夺冠的人w,w从1开始,O(n)枚举2到n每个运动员,若w能战胜 i ,则 i 不可能夺冠;若 i 战胜w,则把w设置为 i ,继续比较。最后得到的 w 是唯一可能夺冠的人,再将w与其他所有运动员比一次,判断w是否能夺冠。
#include<cmath> #include<cstdio> #include<queue> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long const int maxn=50000+50; int T,n,a[maxn][6]; bool p[maxn]; template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } bool pd(int x,int y){ int ans=0; for(int i=1;i<=5;i++) if(a[x][i]<a[y][i]) ans++; if(ans>=3 ) return true; return false; } int main(){ cin>>T; while(T--){ memset(p,false,sizeof(p)); cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=5;j++){ read(a[i][j]); } bool q=0; if(n==1){ cout<<1<<endl; continue; } int w=1; for(int i=2;i<=n;i++){ if(pd(w,i)) continue; else w=i; } for(int i=1;i<=n;i++){ if(i==w) continue; if(!pd(w,i)){ cout<<-1<<endl; q=1; break; } } if(!q) cout<<w<<endl; } return 0; }
2.Codeforces Global Round 15 C. Maximize the Intersections
大意:圆上有2n个点,按顺时针方向给出,给出k次操作,每次操作将指定的两个点相连,剩下的点自由相连,使用过的点不能再使用,求最多能有多少交点?
题解:连接1,3,相当于加入一个 [ 1, 3 ] 的区间,对于两个区间,若他们完全包含或者没有公共部分,则这两条弦没有交点。对于剩下的点,下右连上左,下左连上右。
#include<cmath> #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long const int maxn=300; int T,n,k,down[maxn],up[maxn]; bool p[maxn]; struct node{ int l,r; }a[maxn]; bool pd(int x,int y){ if(a[x].l<a[y].l&&a[x].r>a[y].r) return false; if(a[y].l<a[x].l&&a[y].r>a[x].r) return false; if(a[x].r<a[y].l||a[y].r<a[x].l) return false; return true; } template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ cin>>T; while(T--){ int ans=0; cin>>n>>k; memset(p,false,sizeof(p)); for(int i=1;i<=k;i++){ int x,y; cin>>x>>y; if(x>y) swap(x,y); p[x]=true;p[y]=true; a[i].l=x;a[i].r=y; if(i>=2){ for(int j=1;j<i;j++){ if(pd(i,j)) ans++; } } } int t=1; for(int i=1;i<=2*n;i++){ if(!p[i]&&t<=n-k){ down[t]=i; t++; } else if(!p[i]&&t>n-k){ up[t-(n-k)]=i; t++; } } t=k; for(int i=1;i<=n-k;i++){ a[++t].l=down[i]; a[t].r=up[i]; for(int j=1;j<t;j++) if(pd(t,j)) ans++; } cout<<ans<<endl; } return 0; }
3.Codeforces Round #685 (Div. 2) E1. Bitwise Queries (Easy Version) E2. Bitwise Queries (Hard Version)
大意:有n个数,n为2的整次幂,每个数都在 [ 0, n-1 ] 之间,你有三种询问方式,你可以得到询问的答案,要求在不超过n+2(n+1)次询问中得到这n个数的值,输出询问方式以及这n个数。
题解:(easy version)首先用n-1次把第一个数与后面n-1个数的异或得到,然后注意,a+b = a ^ b + 2*( a & b ) ,所以再用三次把 a[ 1 ] + a[ 2 ] ,a[ 2 ] + a[ 3 ] , a[ 3 ] + a[ 1 ] 的值得到,就可算出a[ 1 ],从而得到这n个数。
(hard version)这列数有两种情况:第一种是存在两个数相等,第二种是 0~n-1 的全排列。 首先依旧用 n-1 次求出 a[ 1 ]与其他数的异或。对于第一种情况,若有a[ 1 ] ^ a[ j ] == a[ 1 ] ^ a[ k ],则 a[ j ] == a[ k ] 由于 a&a = a,所以我们可以询问 a[ j ] & a[ k ],得到答案后就可以算出 a[ 1 ] 的值,共用n次询问;对于第二种情况,可以找到这样一对,a[ 1 ] ^ a[ k ] == n-1,则 a[ 1 ] & a[ k ] == 0,这样我们就直接找到了一组 a[ 1 ] + a[ k ] == n-1 ,再询问两次 a[ 1 ] & a[ j ],a[ k ] & a[ j ] ,就可以像 easy version 那样求出 a[ 1 ],共 n+1 次询问。
hard version 代码
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=100000; int n,a[maxn],w,ans[maxn]; bool p[1000000]; int main(){ cin>>n; bool v=0;int id1,id2; for(int i=2;i<=n;i++){ cout<<"XOR "<<1<<" "<<i<<endl; fflush(stdout); cin>>a[i]; if(!p[a[i]]) p[a[i]]=1; else v=1,id2=i; } if(v){ for(int i=2;i<=n;i++) if(i!=id2&&a[i]==a[id2]){ id1=i; break; } cout<<"AND "<<id1<<" "<<id2<<endl; fflush(stdout); int k; cin>>k; ans[1]=a[id1]^k; } else{ int id1,id2,x,y,z; for(int i=2;i<=n;i++){ if(a[i]==n-1){ id1=i; break; } } x=n-1; if(id1==n) id2=id1-1; else id2=id1+1; cout<<"AND "<<id1<<" "<<id2<<endl;a fflush(stdout); cin>>y;y*=2;y+=(a[id1]^a[id2]); cout<<"AND "<<1<<" "<<id2<<endl; fflush(stdout); cin>>z;z*=2;z+=a[id2]; ans[1]=(x+y+z)/2-y; } for(int i=2;i<=n;i++) ans[i]=(a[i]^ans[1]); cout<<"! "; for(int i=1;i<=n;i++) cout<<ans[i]<<" "; return 0; }
4.Codeforces Round #735 (Div. 2) C. Mikasa
大意:有一列数 n⊕0,n⊕1,……,n⊕m,找出不在这列数中的最小的非负整数。
题解:如果 k 在这列数中,则存在一个 x 满足0 ≤ x ≤ m ,使得 n⊕x=k 。n⊕x=k 等价于 n⊕k=x ,那么问题就可以转化为:求一个最小的 k ,使得 n⊕k ≥ m+1 。那么只需要把m+1和n 的二进制每一位比较贪心选择就可以了。
#include<cmath> #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long const int maxn=105; int T,n,m,a[maxn],b[maxn],ans[maxn]; template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ cin>>T; while(T--){ ll Ans=0; cin>>n>>m; if(n>m){ cout<<0<<endl; continue; } int t1=0,t2=0; while(n){ if(n%2==1) a[++t1]=1; else a[++t1]=0; n/=2; } m++; while(m){ if(m%2==1) b[++t2]=1; else b[++t2]=0; m/=2; } for(int i=1;i<=100;i++) ans[i]=0; for(int i=t1+1;i<=t2;i++) a[i]=0; for(int i=1;i<=t2/2;i++) swap(a[i],a[t2-i+1]); for(int i=1;i<=t2/2;i++) swap(b[i],b[t2-i+1]); for(int i=1;i<=t2;i++){ if(a[i]==0&&b[i]==0) ans[i]=0; else if(a[i]==0&&b[i]==1) ans[i]=1; else if(a[i]==1&&b[i]==0){ ans[i]=0; for(int j=i+1;j<=t2;j++) ans[i]=0; break; } else ans[i]=0; } for(int i=1;i<=t2/2;i++) swap(ans[i],ans[t2-i+1]); ll er=1; for(int i=1;i<=t2;i++){ Ans+=1ll*ans[i]*er; er*=2ll; } cout<<Ans<<endl; } return 0; }
5.Codeforces Round #273 (Div. 2) C. Table Decorations
大意:有红绿蓝三种颜色的气球,个数分别为r,g,b,要求每个桌子上放三个气球,且颜色不完全相同,求最多能放多少桌子?
题解:将三种颜色个数排序,a1,a2,a3,若 a1=a2=a3,则答案为a1;若 a2 = a3,则答案为 a1+( a2+a3-2*a1 ) / 3 ;其他情况则是 每次操作最小的和最大的,最小数-1,最大数-2,然后更新。
#include<cmath> #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long ll a[5]; int main(){ ll ans=0; cin>>a[1]>>a[2]>>a[3]; sort(a+1,a+4); if(a[1]==a[3]){ cout<<a[1]<<endl; return 0; } if(a[2]==a[3]){ cout<<a[1]+(a[2]+a[3]-2*a[1])/3; return 0; } ll cha=a[3]-a[2]; ll num=(cha+1)/2; if(a[1]<=num){ a[3]-=a[1]*2; cout<<a[1]+min(a[2],(a[2]+a[3])/3); } else{ ll s=a[1]-num; a[3]-=num*2; if(s%2==0){ a[2]-=s; a[3]-=s; } else{ a[2]-=((s+1)/2)*2; a[3]-=(s/2)*2; } if(a[2]>a[3]) swap(a[2],a[3]); cout<<a[1]+min(a[2],(a[2]+a[3])/3); } return 0; }
6.Codeforces Round #256 (Div. 2) D. Multiplication Table
大意:给出一个n*m的乘法表,其中 a[ i ][ j ] = i*j ,求表中数字从小到大排序后第 k 个为多少?
题解:二分一个x,判断表中严格小于 x 的数有多少个,找到答案大于等于k的第一个数w,则w-1就为所求数。判断方法为:每一行min( ( x - 1 )/ i,m ) 即为这一行严格小于x的数的个数。
#include<cmath> #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long ll n,m,k; bool check(ll x){ ll ans=0; for(int i=1;i<=n;i++) ans+=min((x-1)/i,m); if(ans<k) return true; return false; } int main(){ cin>>n>>m>>k; ll l=1,r=n*m; while(l<=r){ ll mid=l+r>>1; if(check(mid)) l=mid+1; else r=mid-1; } cout<<l-1; return 0; }
7.Codeforces Round #666 (Div. 1) B. Stoned Game
大意:有n堆石子,第 i 堆有 ai 个,T和HL在玩一个游戏,T先手,两人轮流从这n堆石子中的一堆中拿出一个,且不能与上一个人选择相同的堆,最后不能拿的输,输出胜利者。
题解:首先算出这n堆石子总共有sum个,最多的一堆有max个。(1)若max > sum/2,即先手可以一直拿max这一堆,先手必胜;(2)若max <= sum/2。(i)若sum为偶数,后手必胜,证明如下:当sum为0时,显然后手必胜,当sum>=2时,先手拿走一个石子,此时若最多的一堆满足max > sum/2,则转化为(1) 的情况,后手必胜,若不满足max >sum/2,则可继续进行,直到sum=0。(ii)若sum为奇数,先手拿走一个便可转化为(i)的情况,故先手必胜。
#include<cmath> #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long const int maxn=200; int T,n,a[maxn],sum; int main(){ cin>>T; while(T--){ cin>>n; sum=0; for(int i=1;i<=n;i++){ cin>>a[i]; sum+=a[i]; } sort(a+1,a+1+n); if(a[n]>sum/2){ cout<<"T"<<endl; continue; } if(sum%2==0){ cout<<"HL"<<endl; continue; } cout<<"T"<<endl; } return 0; }
8.Codeforces Round #703 (Div. 2) D. Max Median
大意:给出 n 个数,找出长度不小于 k 的所有子区间,求这些区间中位数的最大值是多少?
题解:考虑二分答案 x,check的时候把小于 x 的数变为 -1,大于等于 x 的数变为 1。若新数组中有长度不小于 k 的子区间且该区间的和大于 0,则 x 合法。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=2e5+50; int n,k,a[maxn],s[maxn],t,b[maxn],sum[maxn]; bool p[maxn]; bool check(int x){ for(int i=1;i<=n;i++){ if(a[i]<x) b[i]=-1; else b[i]=1; sum[i]=sum[i-1]+b[i]; } int Min=0; if(sum[k]>0) return true; for(int i=k+1,j=1;i<=n;i++,j++){ Min=min(Min,sum[j]); if(sum[i]-Min>0) return true; } return false; } template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ cin>>n>>k; for(int i=1;i<=n;i++){ read(a[i]); if(!p[a[i]]) s[++t]=a[i],p[a[i]]=1; } sort(s+1,s+1+t); int l=1,r=t; while(l<=r){ int m=l+r>>1; if(check(s[m])) l=m+1; else r=m-1; } cout<<s[l-1]; return 0; }
9.Codeforces Round #715 (Div. 1) A. Binary Literature
大意:给出3个长度为2n的01串,要求构造一个长度最多为3n的01串,使得这3个01串中至少有2个是该串的子序列。
题解:考虑两个串s和t,可以想到一种构造方案长度为4n-lcs(s,t),那么,只需找到这3个串中 lcs 大于等于n的2个串就行。由于是01串,所以对于每个串必然有0的个数大于n或者1的个数大于n,那么必然存在两个串,他们的公共子序列长度达到n。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=2e5+50; int T,n; char a[maxn],b[maxn],c[maxn]; string ans; void work(char *aa,char *bb,int o){ char op=o+'0',oop; if(op=='1') oop='0'; else oop='1'; int l1=1,l2=1; while(1){ if(l1<=2*n&&l2<=2*n){ if(aa[l1]==bb[l2]){ ans+=aa[l1]; l1++; l2++; continue; } if(aa[l1]==op){ ans+=oop; l2++; continue; } if(bb[l2]==op){ ans+=oop; l1++; continue; } } if(l1>2*n&&l2>2*n) return ; if(l1>2*n){ ans+=bb[l2]; l2++; } else{ ans+=aa[l1]; l1++; } } } template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ cin>>T; while(T--){ cin>>n; ans.clear(); cin>>a+1; cin>>b+1; cin>>c+1; int fa=0,fb=0,fc=0,x=0,y=0; for(int i=1;i<=2*n;i++) if(a[i]=='0') x++; else y++; if(x>y) fa=0; else fa=1; x=0;y=0; for(int i=1;i<=2*n;i++) if(b[i]=='0') x++; else y++; if(x>y) fb=0; else fb=1; x=0;y=0; for(int i=1;i<=2*n;i++) if(c[i]=='0') x++; else y++; if(x>y) fc=0; else fc=1; if(fa==fb){ work(a,b,fa); cout<<ans<<endl; } else if(fa==fc){ work(a,c,fa); cout<<ans<<endl; } else{ work(b,c,fb); cout<<ans<<endl; } } return 0; }
10.Codeforces Global Round 12 C1. Errich-Tac-Toe (Easy Version)
大意:easy版只会给出“ X ”和“ . ”,你可以把“ X ”变成“ O ”,使得行与列上不存在3个“ X ”或者“ O ”连续,设给出“ X ”的数量为 k,则你只能最多改变 k/3 (向下取整)次,求一个构造方案。
题解:将每个点(i,j)按照(i+j)%3 的余数分类,尝试将每一类的“ X ”全部改成“ O ”,统计改变次数,满足则输出,不满足就换一类。可以证明,这3类中一定存在答案。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=330; int T,n; char a[maxn][maxn],b[maxn][maxn]; template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ read(T); while(T--){ cin>>n; int sum=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ cin>>a[i][j]; b[i][j]=a[i][j]; if(a[i][j]=='X') sum++; } int cnt=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if((i+j)%3==1){ if(b[i][j]=='X') b[i][j]='O',cnt++; } } if(cnt<=sum/3){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) cout<<b[i][j]; cout<<endl; } continue; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) b[i][j]=a[i][j]; cnt=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if((i+j)%3==2){ if(b[i][j]=='X') b[i][j]='O',cnt++; } } if(cnt<=sum/3){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) cout<<b[i][j]; cout<<endl; } continue; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) b[i][j]=a[i][j]; cnt=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if((i+j)%3==0){ if(b[i][j]=='X') b[i][j]='O',cnt++; } } if(cnt<=sum/3){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) cout<<b[i][j]; cout<<endl; } continue; } } return 0; }
11.Codeforces Round #584 - Dasha Code Championship - Elimination Round (rated, open for everyone, Div. 1 + Div. 2) G1. Into Blocks (easy version)
大意:给出n个数,每次操作可以修改一个数为任意数,相同的数只能修改成相同的数,例如 [ 3,7,3 ] 中,若修改第一个3为7,则第二个3也必须修改成7。要求修改完成后两个相同的数之间全是该数,即每种数必须连续出现,求最小修改次数。
题解:贪心。记录每种数的数量和每种数出现的最右边的位置,如果某段区间中的数均不在该区间之外出现,则操作这个区间的代价为: 区间长度 - 该区间中出现的最多的数的次数 。答案为每段代价之和。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=200000+50; int n,q,a[maxn],sum[maxn],maxr[maxn]; template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ read(n),read(q); for(int i=1;i<=n;i++) read(a[i]); for(int i=1;i<=n;i++){ sum[a[i]]++; maxr[a[i]]=i; } int r=0,maxx=0,l=1; ll ans=0; for(int i=1;i<=n;i++){ r=max(r,maxr[a[i]]); maxx=max(maxx,sum[a[i]]); if(i==r) ans+=r-l+1-maxx,l=r+1,maxx=r=0; } cout<<ans; return 0; }
12.Codeforces Global Round 12 D. Rating Compression
大意:给出n个数,有长度为 1到 n 的滑动窗口,对于每个长度的滑动窗口,每次求出该窗口中的最小值,若该长度len的滑动窗口所求得的所有数为一个排列,则ans[ len ]=1,否则ans[ len ]=0,输出ans数组。
题解:易得,若长度len的答案为0,则长度2到len的答案均为0。长度1和n需要特判,然后从长度n-1开始,判断该长度所得是否为一个排列,遇到非排列就跳出。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=3e5+50; int T,n,a[maxn],cnt[maxn],ans[maxn]; template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ read(T); while(T--){ read(n); bool p=0,v=0; for(int i=1;i<=n;i++) cnt[i]=0,ans[i]=0; for(int i=1;i<=n;i++){ read(a[i]); cnt[a[i]]++; if(a[i]==1) p=1; if(cnt[a[i]]>1) v=1; } if(!p){ for(int i=1;i<=n;i++) cout<<0; cout<<endl; continue; } ans[n]=1;p=0; if(v) ans[1]=0; else ans[1]=1; int l=1,r=n; for(int i=n;i>=1;i--){ ans[i]=1; int m=n-i+1; if(--cnt[m]==0&&(a[l]==m||a[r]==m)&&cnt[m+1]){ if(a[l]==m) l++; if(a[r]==m) r--; } else break; } for(int i=1;i<=n;i++) cout<<ans[i]; cout<<endl; } return 0; }
13.Codeforces Round #621 (Div. 1 + Div. 2) D. Cow and Fields
大意:给出一个n个点,m条边的无向图,你需要从1走到n,并且会选择走最短路,给出k个特殊点,现在需要在这k个点之间连一条边,并且你希望连边之后的最短路尽可能大,求连边之后的最短路。
题解:首先跑两遍最短路,求出每个特殊点到 1 的最短路 x[ i ] ,到 n 的最短路 y[ i ],则问题转化为,我们需要在这k个点中取两个点a,b,最大化 min(x[ a ] + y[ b ] +1 , x[ b ] + y[ a ] +1)。令 x[ a ] + y[ b ] <= x[ b ] + y[ a ],则我们需要最大化 x[ a ] + y[ b ] +1 ,且满足条件 x[ a ] - y[ a ] <= x[ b ] - y[ b ] 。那么我们可以对这k个点按照 x[ i ] - y[ i ] 排序,排序后枚举一个点 i ,并在 i+1 到 n 中选择一个最大的 b[ j ],得到选择 i 时的最大值 x[ i ] + y[ j ] +1,并对该值取max。最后得到的答案与不加边时的最短路比较,输出min即可。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=2e5+50; const int maxm=4e5+50; int n,m,k,s[maxn],d[maxn],ma[maxn][25]; int fir[maxn],nex[maxm],to[maxm],wi[maxm],ecnt; bool vis[maxn]; void add(int u,int v,int w){ nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;wi[ecnt]=w; } struct node{int x,y;}a[maxn]; int cmp(const node &a,const node &b){return (a.x-a.y)<(b.x-b.y);} priority_queue<pair<int,int> > q; void dijkstra(int x){ memset(vis,false,sizeof(vis)); memset(d,127,sizeof(d));d[x]=0; q.push(make_pair(0,x)); while(!q.empty()){ int u=q.top().second;q.pop(); if(vis[u]) continue; vis[u]=true; for(int e=fir[u];e;e=nex[e]){ int v=to[e]; if(d[v]>d[u]+wi[e]){ d[v]=d[u]+wi[e]; q.push(make_pair(-d[v],v)); } } } } struct RMQ{ int log2[maxn]; void init(){ for(int i=0;i<=n;i++) log2[i]=(i==0?-1:log2[i>>1]+1); for(int j=1;j<=20;j++) for(int i=1;i+(1<<j)-1<=n;i++) ma[i][j]=max(ma[i][j-1],ma[i+(1<<j-1)][j-1]); } int query(int ql,int qr){ int k=log2[qr-ql+1]; return max(ma[ql][k],ma[qr-(1<<k)+1][k]); } }rmq; template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ read(n),read(m),read(k); for(int i=1;i<=k;i++){ read(s[i]); } for(int i=1;i<=m;i++){ int x,y; read(x),read(y); add(x,y,1);add(y,x,1); } dijkstra(1); int Min=d[n]; for(int i=1;i<=k;i++) a[i].x=d[s[i]]; dijkstra(n); for(int i=1;i<=k;i++) a[i].y=d[s[i]]; sort(a+1,a+1+k,cmp); for(int i=1;i<=k;i++) ma[i][0]=a[i].y; rmq.init(); int ans=0; for(int i=1;i<k;i++){ ans=max(ans,1+a[i].x+rmq.query(i+1,k)); } cout<<min(Min,ans)<<endl; return 0; }
14.Codeforces Round #701 (Div. 2) D. Multiples and Power Differences
大意:给定一个矩阵a,你需要求出一个大小与a相同的矩阵b,满足矩阵b中的元素为正整数且均小于等于1e6,b中元素是a中对应元素的倍数,b中任意两个相邻元素之差是一个正整数的4次方。
题解:由于a中的元素小于等于16,所以我们可以先求出1到16的最小公倍数720720,然后b中交替填入720720与720720+a[ i ][ j ]4 即可。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=550; int n,m,a[maxn][maxn],b[maxn][maxn]; template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ read(n),read(m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if((i+j)%2){ cout<<720720<<" "; } else cout<<720720+a[i][j]*a[i][j]*a[i][j]*a[i][j]<<" "; } cout<<endl; } return 0; }
15.Codeforces Round #647 (Div. 1) - Thanks, Algo Muse! B. Johnny and Grandmaster
大意:给出一个n和p,给出n个数k[ i ],表示p的指数,即pk[ i ],将pk[ i ] 分到A,B两个集合里,使得这两个集合的差的绝对值最小,输出这个最小值,对1e9+7取模。
题解:注意到当p≥2时,pn > pn-1+pn-2+...+p,所以,我们先将k[ i ]从大到小排序,记录一个ans,若ans=0,则将当前pk[ i ] 加进ans;若ans>0,则将ans减去pk[ i ]。注意,ans不可能小于0。这样贪心下来得到的ans就是最终答案。
#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=1e6+50; const ll mod1=1e9+7; const ll mod2=1e9+13; ll T,n,p,k[maxn]; int cmp(int a,int b){return a>b;} ll qsm(ll a,ll n,ll mod){ a%=mod;ll ans=1; for(ll i=n;i;i>>=1,a=(a*a)%mod) if(i&1) ans=(ans*a)%mod; return ans%mod; } template<typename T>void inline read(T &aa){ ll ff=1;char cc=getchar();aa=0; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc<='9'&&cc>='0') aa=aa*10+cc-48,cc=getchar(); aa*=ff; } int main(){ read(T); while(T--){ read(n),read(p); ll ans=0,tot=0; for(int i=1;i<=n;i++) read(k[i]); sort(k+1,k+1+n,cmp); for(int i=1;i<=n;i++){ if(ans==0&&tot==0){ ans=(ans+qsm(p,k[i],mod1))%mod1; tot=(tot+qsm(p,k[i],mod2))%mod2; continue; } ans=(ans-qsm(p,k[i],mod1)+mod1)%mod1; tot=(tot-qsm(p,k[i],mod2)+mod2)%mod2; } cout<<ans<<endl; } return 0; }
2021.9.15