The 2024 CCPC Online Contest (D、E、J)

· · 个人记录

Problem D. 编码器-解码器

思路:区间DP,f[i][l][r]代表i-1次操作后,s中形成的t串的[l,r]这个子串的子序列的个数。转移看代码:

diamond:

#include<bits/stdc++.h>
using namespace  std;
#define int long long
#define endl '\n'
const int mod=998244353;
int f[105][105][105];
////F[i][l][r]代表i-1次操作后,s中形成的t串的[l,r]这个子串的子序列的个数。
///考虑怎么转移:如下
void solve(){
    string s,t;
    cin>>s>>t;
    int n=s.size();
    int m=t.size();
    s=" "+s;
    t=" "+t;
    for (int i = 1; i <=n ; ++i) {
        f[i][0][0]=1;
        f[i][0][0]%=mod;
        {       ///我们先不考虑加的s[i]这个字符,那么枚举t的l,r,因为串拼接了,那么新一层的个数肯定
                ///是先由上一层个数×2。
            for (int l = 1; l <= m; ++l) {
                for (int r = l; r <= m; ++r) {
                    f[i + 1][l][r] = f[i][l][r] * 2 % mod;
                    f[i + 1][l][r] %= mod;
                    ////然后再考虑拼接的枚举拼接点j,左边是l到j,右边是j+1到r,乘起来即可。
                    for (int j = l; j < r; ++j) {
                        f[i + 1][l][r] += f[i][l][j] * f[i][j + 1][r] % mod;
                        f[i + 1][l][r] %= mod;
                    }
                }
            }
        }
        ///再把s[i]放到中间后,新形成的包括s[i]的l,r的t的子串算一下
        for (int j = 1; j <=m ; ++j) {
            ///枚举s[i]作为t的第j位
            if(s[i]==t[j]){
                ///首先就是计算一下从l到j的方案数。
                for (int l = 1; l <j ; ++l) {
                    f[i+1][l][j]+=f[i][l][j-1]%mod;
                    f[i+1][l][j]%=mod;
                }
                ///计算一下从j到r的方案数
                for (int r = j+1; r <=m ; ++r) {
                    f[i+1][j][r]+=f[i][j+1][r];
                    f[i+1][j][r]%=mod;
                }
                ///只算s[i]本身的方案也加1
                f[i+1][j][j]+=1;
                f[i+1][j][j]%=mod;
                ///再计算一下j作为某个l到r之间的值的方案数
                ///就是l到j-1的方案×j+1到r的方案,注意判边界,不然容易重复
                for (int l = 1; l <j ; ++l) {
                    for (int r = j+1; r <=m ; ++r) {
                        f[i+1][l][r]+=f[i][l][j-1]*f[i][j+1][r]%mod;
                        f[i+1][l][r]%=mod;
                    }
                }
            }
        }
    }
    cout<<f[n+1][1][m]<<endl;
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
}

Problem E. 随机过程

思路:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define endl '\n'
const int mod=998244353;
int ksm(int a,int b){
    int res=1;
    while(b){
        if(b&1){
            res=res*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    int ans=0;
//  for(int i=0;i<=10;i++){
//      cout<<ksm(26,i)<<endl;
//  }
    for(int i=0;i<=m;i++){
        if(i<=5)
        ans+=min(n,ksm(26,i));
        else{
            ans+=n;
        }
        ans%=mod;

    }
    cout<<ans<<' ';
    ans=1;
    int d=ksm(26,mod-2);
    for(int i=1;i<=m;i++){
        int a=ksm(d,i);
        int p=(1-a+mod)%mod;
        int b=ksm(p,n);
        ans+=(1-b+mod)%mod*ksm(26,i)%mod;
        ans%=mod;
    }
    cout<<ans<<endl;
}

Problem J. 找最小

思路:对于ai和bi交换操作,可以看做将ai和bi都异或(ai异或bi),那么首先计算出a和b数组的异或和x和y,就是选择一些z=ai异或bi,将x和y都异或上z,使得max(x,y)最小,对于数组选择某些进行异或,可以先求出这个数组的线性基进行解决,这样就可以把长度为n的数组缩小成32位的数组,对于这个数组线性基上每一位的数字,都是极大无关的,要想使得这一位为1,必须选择他才行。那么我们可以从高位向低位贪心。

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define int long long
#define PII pair<int,int>
#define endl '\n'
typedef long long ll;
const int MN=31,N=1e6+3;
ll w[33],tmp[33];
bool flag;
int n;
int a[N],b[N];
void ins(ll x){
    for( int i=MN;~i;i--)
        if(x&(1ll<<i))
            if(!w[i]){w[i]=x;return;}
            else x^=w[i];
    flag=true;
}
ll qmax(ll res=0){
    for( int i=MN;~i;i--)
        res=max(res,res^w[i]);
    return res;
}
ll qmin(){
    if(flag)return 0;
    for( int i=0;i<=MN;i++)
        if(w[i])return w[i];
}
void solve() {

    cin>>n;

    flag=0;
    for (int i = 0; i <32 ; ++i) {
        w[i]=0;
    }
    int res1=0;
    int res2=0;
    for (int i = 0; i <n ; ++i) {
        cin>>a[i];
    }
    for (int i = 0; i <n ; ++i) {
        cin>>b[i];
        res1^=a[i];
        res2^=b[i];
        ins(a[i]^b[i]);
    }
    string a1=bitset<32>(res1).to_string();
    string a2=bitset<32>(res2).to_string();
//    cout<<a1<<endl<<a2<<endl;
//    cout<<endl;
//    for (int i = MN; i >=0 ; --i) {
//       // cout<<w[i]<<' ';
//        string a1=bitset<32>(w[i]).to_string();
//    //    cout<<a1<<endl;
//    }
  //  cout<<endl;
   // cout<<res1<<' '<<res2<<endl;
    int ans=max(res1,res2);
    for (int i = 31; i >=0 ; --i) {
        if(w[i]==0)continue;
        int d1 = res1 >> i & 1ll;
        int d2 = res2 >> i & 1ll;
        if (d1 and d2) {

            if (w[i]) {
                res1 ^= w[i];
                res2 ^= w[i];
                ans=min(ans,max({res1,res2}));
            } else {
                continue;
            }
        }
        else if (d1 == 0 and d2 == 0) {
            continue;
        }
        else if(d1){
        //    cout<<i<<endl;
            int tm2=res2;
            int tm1=res1;
            tm1^=w[i];
            tm2^=w[i];
            for (int j = i-1; j>=0 ; --j) {
                int d2=tm2>>j&1;
                if(d2){
                    if(w[j]){
                        tm2^=w[j];
                        tm1^=w[j];
                    }
                }
            }
            ans=min(ans,max(tm1,tm2));

            tm2=res2;
            tm1=res1;
            for (int j = i-1; j>=0 ; --j) {
                int d1=tm1>>j&1;
                if(d1){
                    if(w[j]){
                        tm1^=w[j];
                        tm2^=w[j];
                    }
                }
            }
            ans=min(ans,max(tm1,tm2));

            break;
        }
        else if(d2 ){
          //  cout<<i<<endl;
            int tm2=res2;
            int tm1=res1;
            for (int j = i-1; j>=0 ; --j) {
                int d2=tm2>>j&1;
                if(d2){
                    if(w[j]){
                        tm2^=w[j];
                        tm1^=w[j];
                    }
                }
            }
            ans=min(ans,max(tm1,tm2));

            tm2=res2;
            tm1=res1;
            tm1^=w[i];
            tm2^=w[i];
            for (int j = i-1; j>=0 ; --j) {
                int d1=tm1>>j&1;
                if(d1){
                    if(w[j]){
                        tm1^=w[j];
                        tm2^=w[j];
                    }
                }
            }
            ans=min(ans,max(tm1,tm2));

            break;
        }
    }
    cout<<ans<<endl;

}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }

    return 0;
}