cf1

1.Codeforces Round #729 (Div. 2)  B. Plus and Multiply

 

 

 

题解:枚举 a 的次方,若 n 减去 a 的次方是 b 的整倍数,则 n 满足要求,注意特判 a = 1 与 b = 1 。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
 
ll T,n,a,b;
 
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--){
        bool p=0;
        read(n),read(a),read(b);
        if(b==1){
            printf("Yes\n"); continue;
        }
        if(a==1){
            if((n-1)%b==0) printf("Yes\n");
            else printf("No\n");
            continue;
        }
        for(ll i=1;i<=n;i*=a){
            if((n-i)%b==0){
                printf("Yes\n");
                p=1;break;
            }
        }
        if(!p){
            printf("No\n");
        }
    }
    return 0;
}
View Code

 

2.Codeforces Round #724 (Div. 2) C. Diluc and Kaeya

 

 

 

 

 大意:给定DK序列的所有前缀中,对于每个前缀可以分为k段,使得分为的k段长度相同,且每段中D与K数量之比相同,求对于每个前缀这个k的最大值。

 题解:将D出现的次数记为x,K出现的次数记为y,用(x,y)表示每个前缀,可得到坐标系中的n个点。其中,第 i 个点与原点相连穿过第 1~i 个点的数量就为答案。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
 
const int maxn=5e5+5; 
 
int T,n;
char a;
 
int gcd(int a,int b){
    int c;
    while(a%b){
        c=a%b;
        a=b;
        b=c;
    }
    return b;
}
 
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--){
        map<pair<int,int>,int > mp;
        int sum1=0,sum2=0;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a;
            if(a=='D') sum1++;
            else sum2++;
            pair<int,int> c;
//            cout<<sum1<<" "<<sum2<<endl;
            if(sum1==0){
                c.first=0;c.second=0;
            }
            else if(sum2==0){
                c.first=1;c.second=0;
            }
            else{
                int g=gcd(sum1,sum2);
//                cout<<g<<endl;
                int x1=sum1/g,x2=sum2/g;
                c.first=x1;c.second=x2;
            }
            mp[c]++;
            cout<<mp[c]<<" ";
        }
        cout<<endl;
    }
    
    return 0;
}
View Code

 

3.Codeforces Round #645 (Div. 2) Celex Update

 

 

 

 

 大意:每次只能向下或者向右走,问两点间经过数字之和不同的路径有多少条?

 题解:起点为(x1,y1),终点为(x2,y2),则答案为(x2-x1)*(y2-y1)+1 。

 

4.Codeforces Round #645 (Div. 2)  D. The Best Vacation

 

 

 

 

 大意:一年有n个月,第 i 个月有 d[i] 天,而每个月的第 k 天可以获得 k 点拥抱。你要旅游连续 x 天,问可以获得拥抱的最大值为多少?

 题解:贪心可以发现,获得最大值时,旅游总是在某个月的最后一天结束。枚举每个月,假定这个月的最后一天结束,向前二分找到开始的月份,统计答案,取max。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
 
const int maxn=4e5+50;
 
ll n,x,d[maxn];
ll Sum[maxn],tot[maxn];
 
int find(int k,int l,int r){
    if(l==r) return l;
    int m=l+r>>1;
    if(Sum[k]-Sum[m]<x) return find(k,l,m);
    return find(k,m+1,r);
}
 
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>>x;
    ll sum=0,Max=0;
    for(int i=1;i<=n;i++){
        read(d[i]); d[i+n]=d[i];
    }
    for(int i=1;i<=2*n;i++){
        Sum[i]=Sum[i-1]+d[i];
        tot[i]=tot[i-1]+(d[i]+1)*d[i]/2;
    } 
    for(int i=1;i<=2*n;i++){
        if(Sum[i]<x) continue;
        int y=find(i,1,i);
        ll num=x-Sum[i]+Sum[y];
        Max=max(Max,tot[i]-tot[y]+(d[y]*2+1-num)*num/2);
    }
    cout<<Max<<endl;
    return 0;
}
View Code

 

5.Codeforces Round #722 (Div. 2) C. Parsa's Humongous Tree

 

 

 

 

 大意:一棵树的每个节点有两个值 l [ i ] 和 r [ i ] ,这个节点的权值为 a[ i ],a要满足 l [i] <= a [i] <= r [i] ,一条路径的值为路径两点的权值之差的绝对值,求所有路径的值之和的最大值。

 题解:dp[ i ][ 0 ] 和 dp[ i ][ 1 ] 分别表示  i  节点取左、右值时其子树路径之和的最大值,设 v 是 i 的子节点,则有

            dp[ i ][ 0 ]  += max( dp[ v ][ 0 ] + abs( l[ i ] - l[ v ] ) , dp[ v ][ 1 ] + abs( l[ i ] - r[ v ] ) )

            dp[ i ][ 1 ]  += max( dp[ v ][ 0 ] + abs( r[ i ] - l[ v ] ) , dp[ v ][ 1 ] + abs( r[ i ] - r[ v ] ) )

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long 

const int maxn=2e5+50;
const int maxm=4e5+50;

int T,n,l[maxn],r[maxn];
int fir[maxn],nex[maxm],to[maxm],ecnt; 
ll dp[maxn][2];

void add(int u,int v){
    nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
} 

void dfs(int x,int f){
    dp[x][0]=dp[x][1]=0;
    for(int e=fir[x];e;e=nex[e]){
        int v=to[e];
        if(v==f) continue;
        dfs(v,x);
        dp[x][0]+=max(dp[v][0]+abs(l[x]-l[v]),dp[v][1]+abs(l[x]-r[v]));
        dp[x][1]+=max(dp[v][0]+abs(r[x]-l[v]),dp[v][1]+abs(r[x]-r[v]));
    }
}

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--){
        memset(fir,0,sizeof(fir));
        memset(nex,0,sizeof(nex));
        memset(to,0,sizeof(to)); ecnt=0;
        cin>>n;
        for(int i=1;i<=n;i++){
            read(l[i]),read(r[i]); 
        }
        int x,y;
        for(int i=1;i<n;i++){
            read(x),read(y);
            add(x,y);add(y,x) ;
        }
        dfs(1,0);
        cout<<max(dp[1][0],dp[1][1])<<endl;
    }
    return 0;
}
View Code

 

6.Codeforces Round #264 (Div. 2) D. Gargari and Permutations

 

 

 大意:求 k 个 n 的全排列的最长公共子序列

 题解:(1)可以将 k 个序列中均满足 i 出现在 j 的前面的 i 与 j 连边,求最长路

              (2)   设dp[ i ] 为在第一个序列中到 i 能与所有序列形成的最长公共子序列长度,则往 i 后面枚举 j ,如果 a[ j ] 在其他序列中出现的位置均在 a[ i ] 后面,则 dp[ j ] = max( dp[ j ] , dp[ i ] +1 )。

                      最后将 dp[ i ] 取 max

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=1000+50;
const int maxm=1e6+5;

int n,k,a[6][maxn],id[6][maxn],dp[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>>n>>k;
    for(int i=1;i<=k;i++){
        for(int j=1;j<=n;j++){
            read(a[i][j]);
            id[i][a[i][j]]=j;
        }
    }
    for(int i=1;i<=n;i++) dp[i]=1;
    for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++){
        bool p=0;
        for(int t=2;t<=k;t++){
            if(id[t][a[1][j]]<=id[t][a[1][i]]){
                p=1;break;
            }
        }
        if(p) continue;
        dp[j]=max(dp[j],dp[i]+1);
    }
    int ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
    cout<<ans;
    return 0;
}
View Code

 

7.Codeforces Round #486 (Div. 3) D. Points and Powers of Two

 

 

 大意:给定n个数,找出最多的数,使他们任意两个数之差的绝对值为二的整次幂

 题解:可以证明,最多只能找出3个数。枚举大小为中间的数为a,枚举2的次幂 k,查找 a-k 与 a+k 是否存在,存在则答案为3。若不存在继续判断答案为 2 的情况即可。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=2e5+50;

ll n,a[maxn],br,t=1,ans;
ll er[100];

bool find(ll x,int l,int r){
    if(l==r){
        if(a[l]!=x) return false;
        return true;
    }
    int m=l+r>>1;
    if(a[m]<x) return find(x,m+1,r);
    if(a[m]>x) return find(x,l,m);
    if(a[m]==x) return true;
}

bool pd(int x){
    for(int i=0;i<=t;i++)
    if(x%er[i]==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;
    er[0]=1;
    for(int i=1;;t++,i++){
        er[i]=er[i-1]*2;
        if(er[i]>2e9) break; 
    } 
    for(int i=1;i<=n;i++) read(a[i]);
    sort(a+1,a+1+n);
    if(n==1){
        ans=1;
        cout<<ans<<endl<<a[1]; return 0;
    }
    if(n==2){
        if(pd(a[2]-a[1])){
            ans=2;
            cout<<ans<<endl<<a[1]<<" "<<a[2]; return 0;
        }
        else{
            ans=1;
            cout<<ans<<endl<<a[1]<<" ";return 0;
        }
    }
    for(int i=2;i<n;i++){
        for(int j=0;j<=t;j++){
            ll x=a[i]-er[j],y=a[i]+er[j];
            if(find(x,1,i-1)&&find(y,i+1,n)){
                ans=3;
                cout<<ans<<endl<<x<<" "<<a[i]<<" "<<y;return 0;
            }
        }
    }
    for(int i=1;i<n;i++){
        for(int j=1;j<=t;j++){
            ll x=a[i]+er[j];
            if(find(x,i+1,n)){
                ans=2;
                cout<<ans<<endl<<a[i]<<" "<<x; return 0;
            }
        }
    }
    ans=1;
    cout<<ans<<endl<<a[1];
    return 0;
}
View Code

 

8.Codeforces Round #731 (Div. 3) E. Air Conditioners

 

 

 

 

 

 大意:有n个点,k个空调,给出每个空调的位置a[ i ]和温度 t[ i ],对于一个点 i ,它的温度为,求每个点的温度

 

 题解:设L[ i ] 表示点 i 以及 i 左边的点对 i 的贡献,即 i 点有空调时 L[ i ] = min ( L[ i-1 ] +1 , t[ i ] ) , 否则 L [ i ] = L[ i-1 ] + 1

同样,设R[ i ] 表示点 i 以及 i 右边的点对 i 的贡献,即 i 点有空调时 R[ i ] = min ( R[ i+1 ] +1, t[ i ] ), 否则 R [ i ] = R[ i+1 ] + 1

最后 i 点的答案就为 min( L[ i ] , R[ i ] )

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=3e5+50;
const int maxx=2e9;

ll L[maxn],R[maxn],T[maxn];
int TT,n,k;
bool P[maxn];

struct node{
    int p; ll t;
}a[maxn];

int cmp(const node &a,const node &b){
    return a.p<b.p;
}

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>>TT;
    while(TT--){
        cin>>n>>k;
        memset(P,0,sizeof(P));
        for(int i=1;i<=k;i++){
            read(a[i].p);
            P[a[i].p]=true;
        } 
        for(int i=1;i<=k;i++) read(a[i].t);
        for(int i=1;i<=k;i++) T[a[i].p]=a[i].t;
        for(int i=0;i<=n+1;i++) L[i]=maxx,R[i]=maxx;
        sort(a+1,a+1+k,cmp);
        for(int i=a[1].p;i<=n;i++){
            if(P[i]) L[i]=min(L[i-1]+1,T[i]);
            else L[i]=L[i-1]+1;
        }
        for(int i=a[k].p;i>=1;i--){
            if(P[i]) R[i]=min(R[i+1]+1,T[i]);
            else R[i]=R[i+1]+1;
        }
        for(int i=1;i<=n;i++) cout<<min(L[i],R[i])<<" ";
        cout<<endl;
    }
    return 0;
}
View Code

 

9.Codeforces Round #732 (Div. 2) B. AquaMoon and Stolen String

 

 

 

 

 

 

 

 

 大意:有奇数n个字符串,将其中n-1个两两配对,一对字符串中相同位置可以交换,如aaaa与bbbb可以交换为aabb与bbaa,给出这n-1个交换后的串,求剩下的那一个串

 题解:注意 a^b^b = a , 对于输入的 2*n-1 个串,对他们的位置 i 进行异或,得到的答案就是剩下的那个串的位置 i 。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=2e5+50;

int T,n,m;
string a[maxn];

int main(){
    cin>>T;
    while(T--){
        cin>>n>>m;
        for(int i=1;i<=2*n-1;i++) cin>>a[i];
        for(int i=0;i<m;i++){
            int cur=0;
            for(int j=1;j<=2*n-1;j++) 
            cur^=(a[j][i]-'a');
            cout<<char(cur+'a');
        }
        cout<<endl;
    }
    return 0;
}
View Code

 

10.Codeforces Round #732 (Div. 2)C. AquaMoon and Strange Sort

 

 

 

 

 大意:有n个数,他们的方向开始都朝右,每次操作可以将一个数与它相邻的数交换,同时这两个数的方向改变,问能不能使得这n个数不降排列且每个数的方向都向右?

 题解:方向不变,则每个数都要交换偶数次。记录原数列中每个数出现的奇数位置、偶数位置的次数,再将数列排序,若排序后的数列中每个数出现在奇数、偶数位置的次数与原数列不同,则不满足;否则满足。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=1e5+50;

int T,n,a[maxn],odd[maxn],even[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--){
        memset(odd,0,sizeof(odd));
        memset(even,0,sizeof(even));
        cin>>n;
        for(int i=1;i<=n;i++){
            read(a[i]);
            if(i%2) odd[a[i]]++;
            else even[a[i]]++;
        }
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++){
            if(i%2) odd[a[i]]--;
            else even[a[i]]--;
        }
        bool p=0;
        for(int i=1;i<=1e5;i++){
            if(even[i]!=0||odd[i]!=0){
                p=1;break;
            }
        }
        if(p){
            cout<<"NO"<<endl;
        }
        else cout<<"YES"<<endl;
    }
    return 0;
}
View Code

 

11.The 2020 ICPC Asia Macau Regional Contest F. Fixing Networks

 

 

 

 

 大意:有n个点,要求每个点恰好与d个点相连,且这n个点分为c块,块内各点连通,块与块之间不连通,能否构造?

 题解:每个点需要连接d个点,则一块至少需要d+1个点,即( d+1 )*c 需要小于等于n,同时,n和d不能都为奇数。单独判断d=0和d=1,对于其他情况,取d+1个点为一个块,这个块内的点两两相连,可以构造

c-1个这样的块。对于剩下的m个点,它们需要构成一块,取 k=d/2 (向下取整),这m个点每个点向其前后k个点分别连边,若d为奇数,此时m必然为偶数,则再将每个点与其对称点连边即可。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
 
ll n,d,c,ans[100000+50],t;
 
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>>d>>c;
    if((d+1)*c>n||(n%2&&d%2)){
        cout<<"No"<<endl; return 0;
    }
    if(d==0){
        if(n==c){
            cout<<"Yes"<<endl;
        }
        else{
            cout<<"No"<<endl;
        }
        return 0;
    }
    if(d==1){
        if(n==2*c){
            cout<<"Yes"<<endl;
            for(int i=1;i<=n;i++){
                if(i%2) cout<<i+1<<endl;
                else cout<<i-1<<endl;
            }
        }
        else{
            cout<<"No"<<endl;
        }
        return 0;
    }
    cout<<"Yes"<<endl;
    for(int i=1;i<=(c-1)*(d+1);i++){
        ll id=(i-1)/(d+1),st=id*(d+1)+1,ed=(id+1)*(d+1);
        for(int j=st;j<=ed;j++){
            if(j==i) continue;
            cout<<j<<" ";
        }
        cout<<endl;
    }
    ll k=d/2,sum=n-(c-1)*(d+1),st=(c-1)*(d+1)+1;
    for(int i=st;i<=n;i++){
        t=0;
        for(int j=i+1;j<=i+k;j++){
            if(j>n) ans[++t]=j-sum;
            else if(j<st) ans[++t]=j+sum;
            else ans[++t]=j;
        }
        if(d%2){
            int x=i+sum/2; if(x>n) x-=sum;
            ans[++t]=x;
        }
        for(int j=i-k;j<=i-1;j++){
            if(j>n) ans[++t]=j-sum;
            else if(j<st) ans[++t]=j+sum;
            else ans[++t]=j;
        }
        sort(ans+1,ans+1+t);
        for(int i=1;i<=t;i++) cout<<ans[i]<<" ";
        cout<<endl;
    }
    return 0;
}
 
View Code

 

12.The 2020 ICPC Asia Macau Regional Contest G. Game on Sequence

 

 

 

 

 大意:有一个长度为n的序列,Grammy和Alice在这个序列上玩一个游戏,他们从位置k开始,Grammy先进行,每次他们需要从当前数向后跳,且要满足跳到的数与当前数在二进制表示上最多一位不同,最后不能跳的人输掉游戏。现在有m个操作,操作 1 k 表示在这个序列的最后面加上一个数 k ,操作 2 k 表示游戏从位置 k 开始,输出谁能赢下这个游戏。

 题解:对于两个位置 i,j ( i<j ) 并且 a[ i ] = a[ j ] ,若 a[ j ]必败,由于a[ i ]可以跳到 a[ j ],则a[ i ]必胜;若a[ j ] 必胜,表示a[ j ]可以跳到后面一个必败的点,则a[ i ]同样可以跳到那个点,a[ i ]必胜。可以看出,如果一个数后面有与它相同的数,则这个数必胜。所以只需要判断一个数最后出现的位置能不能必胜。从后向前推,若当前数可以跳到的数中,有必败的数,则当前数必胜,否则当前数必败。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn=4e5+50;

int n,m,a[maxn],loc[maxn];
bool f[maxn];

int cmp(int x,int y){
    return loc[x]>loc[y];
}

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

void work(){
    int lim=256;
    memset(f,1,sizeof(f));
    vector<int> v;
    for(int i=0;i<lim;i++){
        if(loc[i]) v.push_back(i);
    }
    sort(v.begin(),v.end(),cmp);
    for(int i=0;i<v.size();i++){
        bool p=0;
        int x=v[i];
        for(int k=0;k<8;k++)
        if(!f[x^(1<<k)]) p=1;
        if(p) f[x]=1;
        else f[x]=0;
    }
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        read(a[i]);
        loc[a[i]]=i;
    }
    work();
    int op,k;
    while(m--){
        cin>>op>>k;
        if(op==1){
            a[++n]=k;
            loc[k]=n;
            work();
        }
        else{
            if(loc[a[k]]==k){
                if(f[a[k]]) cout<<"Grammy"<<endl;
                else cout<<"Alice"<<endl;
            }
            else cout<<"Grammy"<<endl;
        }
    }
    return 0;
}
View Code

 

13.Codeforces Round #721 (Div. 2) C. Sequence Pair Weight

 

 

 

 

 大意:一个序列中,一对相同元素可以提供一重量,给定一个n个数的序列,求这个序列的所以子串 ( 包括自己且要求连续 )的重量的和。

 题解:设dp[ i ]为以第 i 位结束的所有串的重量和,则答案为dp[ 1 ] + dp[ 2 ] +...+ dp[ n ]。对于第 i 位,如果在第 j 位 ( j < i )的数a[ j ] = a[ i ],则它的贡献为 j ,所以 dp[ i ] = dp[ i-1 ] + ∑ j ( j < i,且a[ j ] = a[ i ] )

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn=1e5+50;

ll T,n,a[maxn];
ll dp[maxn];

map<ll,ll> mp;

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--){
        mp.clear();
        read(n);dp[0]=0; ll ans=0;
        for(int i=1;i<=n;i++){
            read(a[i]);
            mp[a[i-1]]+=i-1;
            dp[i]=dp[i-1]+mp[a[i]];
            ans+=dp[i];
        }
        cout<<ans<<endl;
    }
    return 0;
}
View Code

 

14.Codeforces Round #683 (Div. 2, by Meet IT) D. Catching Cheaters

 

 

 

 

 

 

 

 

 大意:给你两个字符串A和B,C和D分别为A和B的子串,定义S(C,D) = 4*LCS(C,D) - |C| - |D| ,其中 LCS(C,D) 表示C和D的最长公共子序列,对于A和B的任意子串C和D,求出S(C,D) 的最大值。

 题解:设dp[ i ][ j ] 为以a[ i ] 结尾,b[ j ]结尾的两个串的最大S值,枚举 i,j,如果a[ i ] = b[ j ],则 LCS增加1,S值增加2,有dp[ i ][ j ]=max( dp[ i ][ j ], dp[ i-1 ][ j-1 ] + 2 );如果 a[ i ] ≠ b[ j ],则 dp[ i ][ j ] = max( dp[ i ][ j ],dp[ i ][ j-1 ] -1 ) ,dp[ i ][ j ] = max( dp[ i ][ j ],dp[ i-1 ][ j ] -1 )。最后对每个dp[ i ][ j ] 取max得到答案。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
 
const int maxn=5050;
 
int n,m,dp[maxn][maxn],ans;
char a[maxn],b[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>>n>>m;
    cin>>a+1;
    cin>>b+1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
        if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+2;
        else{
            dp[i][j]=max(dp[i][j],dp[i-1][j]-1);
            dp[i][j]=max(dp[i][j],dp[i][j-1]-1);
        }
        ans=max(ans,dp[i][j]);
    }
    cout<<ans<<endl;
    return 0;
}
View Code

 

15.The 15th Heilongjiang Provincial Collegiate Programming Contest C. Cornelia Street

 

 大意:一个字符串S由 AA....ABBB...BAA..Aa 组成,其中A与B的长度相同,但数量不一定相同,a是A的一个前缀,求最短的A,B。

 题解:先求出整个串的hash值,枚举所求长度,算出每段的hash值,若除开A的前缀a之外只有两种hash值,则满足要求。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=8e5+50;
const ll base=131;
const ll mod=1e9+7;

char a[maxn];
ll hhash[maxn],ans,mul[maxn];

int main(){
    cin>>a+1;
    int len=strlen(a+1);mul[0]=1;
    for(int i=1;i<=len;i++) hhash[i]=(hhash[i-1]*base+(ll)a[i])%mod,mul[i]=mul[i-1]*base%mod;
    int id;
    for(int l=1;l<=len/2;l++){
        int tot=0;ll sum=0,pre; bool p=0;
        for(int i=l;i<=len;i+=l){
            ll pp=hhash[i]-mul[l]*hhash[i-l]%mod;
            if(pp<0) pp+=mod;
            if(sum!=pp){
                if(sum==0) pre=pp;
                if(tot==1) id=i-l+1;
                sum=pp; tot++;
                if(tot>=3){
                    if(tot==3&&sum==pre) continue;
                    p=1;break;
                }
            }
        }
        if(p) continue;
        int las=len%l;
        if((hhash[len]-mul[las]*hhash[len-las]%mod+mod)%mod==hhash[las]){
            ans=l; break;
        }
    }
//    cout<<ans<<endl;
    for(int i=1;i<=ans;i++) cout<<a[i]; cout<<" ";
    for(int i=id;i<=id+ans-1;i++) cout<<a[i];
    return 0;
}
View Code

 

 

2021.7.16

 

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