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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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 ]即可。

#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;
}
View Code

 

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;
}
View Code

 

2021.9.15

posted @ 2021-07-26 09:37  rld  阅读(423)  评论(0编辑  收藏  举报