• Educational Codeforces Round 107 题解(A-E)


    比赛链接

    A题

    大意

    思路

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef pair<int,int> pii;
    typedef long long ll;
    const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    int n,l,r,s;
    int a[maxn];
    int vis[maxn];
    signed main(){
        int _;scanf("%d",&_);
        while(_--){
            scanf("%d",&n);
            int cnt=0;
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                if(a[i]==1||a[i]==3){
                    cnt++;
                }
            }
            printf("%d
    ",cnt);
    
        }
        return 0;
    }
     
    

    B题

    大意

    要你构造数字(x)(a)位,数字(y)(b)位,(gcd(x,y))(c)

    (1le a,ble9,1le cle min(a,b))

    求数字(x,y)均不含有前导(0)

    思路

    构造方法有很多种

    我是构造成(x=2^{k1} imes 10^{c-1}),(y=3^{k2} imes 10^{c-1})

    显然这样符合题意

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef pair<int,int> pii;
    typedef long long ll;
    const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    int a,b,c;
    int cal(ll x){
        int cnt=0;
        while(x){
            cnt++;
            x=x/10;
        }
        return cnt;
    }
    signed main(){
        int _;scanf("%d",&_);
        while(_--){
            scanf("%d%d%d",&a,&b,&c);
            ll ans1=1,ans2=1;
            c--;
            while(c--){
                ans1=ans1*10;
                ans2=ans2*10;
            }
            while(cal(ans1)!=a){
                ans1=ans1*2;
            }
            while(cal(ans2)!=b){
                ans2=ans2*3;
            }
            printf("%lld %lld
    ",ans1,ans2);
    
        }
        return 0;
    }
     
    

    C题

    大意

    有一个长度为(n(2le nle 3e5))的数组(a(1le a[i]le50))

    现在有(q(1le q le 3e5))次查询,每次查询一个数(x(1le xle50))

    要你找到一个最小的位置(pos)(a[pos]=x)

    输出(pos)并且把这个值放到首位,其他位置进行相应的移动

    思路

    主要是要发现总共只有(50)类数,并且你会发现,每个答案其实都是每一类的位置最小值

    而你把你移动到第一位,那么它的位置依然是这一类的最小值,所以只要维护(50)类的位置最小值即可

    其他的不要考虑

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef pair<int,int> pii;
    typedef long long ll;
    const int maxn=3e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    int n,q;
    int mi[100];
    int ans[maxn];
    signed main(){
        scanf("%d%d",&n,&q);
        for(int i=1,x;i<=n;i++){
            scanf("%d",&x);
            if(mi[x]==0){
                mi[x]=i;
            }
        }
        for(int i=1,x;i<=q;i++){
            scanf("%d",&x);
            ans[i]=mi[x];
            for(int j=1;j<=50;j++){
                if(mi[j]<mi[x]){
                    mi[j]++;
                }
            }
            mi[x]=1;
        }
        for(int i=1;i<=q;i++){
            printf("%d ",ans[i]);
        }
        return 0;
    }
     
    

    D题

    大意

    要你构造一个长度为(n(nle2e5))的字符串,且只能使用前(k)位小写字母

    要使得(s[i]=s[j]&&s[i+1]=s[j+1])的次数最小

    任意输出一组解

    思路

    显然就是把相邻的两个字符当作一个整体

    那么最多有(k^2)种组合

    所以我只要构造前(k^2)的长度即可

    要他们出现(k^2-1)种组合

    (s[k^2+1]=s[1])

    (s[k^2]s[k^2+1])这两个字符为最后一组合

    那么让第一个元素为(a)

    然后遍历的时候从第(k)个字母,从大到小遍历到最小的字母(a)

    这样恰好使得(aa)没有出现过

    我也不知道怎么证明其一定可以构造成功

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef pair<int,int> pii;
    typedef long long ll;
    const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    int n,k;
    char s[maxn];
    bool vis[300][300];
    signed main(){
        scanf("%d%d",&n,&k);
        s[1]='a';
        for(int i=2;i<=k*k;i++){
            for(int j=k;j>=1;j--){
                if(!vis[s[i-1]-'a'+1][j]){
                    vis[s[i-1]-'a'+1][j]=1;
                    s[i]=j+'a'-1;
                    break;
                }
            }
        }
        int len=k*k;
        for(int i=1;i<=n;i++){
            printf("%c",s[(i-1)%len+1]);
        }
        return 0;
    }
     
    

    E题

    大意

    给你一个(n imes m(n imes mle3e5))的矩阵

    其中有黑点和白点

    你可以对白点进行染色,使白点变为红点或蓝点

    求在所有情况中你最多可以在这个图中放多少个多米诺骨牌的总和(mod 998244353)

    多米诺骨牌放置的规则如下

    • 每个多米诺骨牌覆盖两个相邻的单元格;
    • 每个单元最多覆盖一个多米诺骨牌;
    • 如果将多米诺骨牌水平放置(它覆盖一行中的两个相邻单元格),则它应仅覆盖红色单元格;
    • 如果将多米诺骨牌垂直放置(它覆盖其中一列中的两个相邻单元格),则它应仅覆盖蓝色单元格。

    思路

    本质上是个概率论问题qwq

    首先设有(cnt)个白点,假设期望为(e),那么答案就是(2^{cnt} imes e),所以你只要求出期望即可

    假设现在这个图是固定的,你已知哪些点为蓝色,哪些点为红色

    那么你可以使用贪心的策略来计算到底有多少个多米诺骨牌

    假设((x,y))((x,y+1))能够构成一个多米诺骨牌,那么代表这两个都被染成红色

    ((x,y+1))左边的连续红色的点必定是偶数,如果为奇数,那么((x,y))将会和((x,y-1))进行配对

    所以假设((x,y))若和((x,y-1))变成多米诺骨牌

    • ((x,y-1))前面没有白点,那么概率为(frac{1}{4}),相当于把这两个点直接变成红色

    • ((x,y-1))前面有一个白点,那么概率为(frac{1}{4}-frac{1}{8}),相当于这两个点为红色,减去三个点都是红色情况

    • ((x,y-1))前面有两个白点,那么概率为(frac{1}{4}-frac{1}{8}+frac{1}{16}),相当于这两个点为红色,减去最后三个点都是红色情况,然后加上四个点都是红色的情况

    以此类推

    然后变成蓝点也是同理的,建议可以看官方题解更加详细

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef pair<int,int> pii;
    typedef long long ll;
    const int maxn=3e5+5,inf=0x3f3f3f3f,mod=998244353;
    const double eps=1e-6;
    const ll ni=499122177;
    // ni为2的逆元
    int n,m;
    string s[maxn];
    ll fac[maxn],finv[maxn];
    ll base[maxn];
    ll qpow(ll a,ll b){
        ll ans=1,base=a;
        while(b){
            if(b%2){
                ans=ans*base%mod;
            }
            base=base*base%mod;
            b=b>>1;
        }
        return ans;
    }
    signed main(){
        fac[0]=finv[0]=1;
        for(int i=1;i<=3e5;i++){
            fac[i]=fac[i-1]*2%mod;
            // fac[i]=2^i
            finv[i]=finv[i-1]*ni%mod;
            // finv[i]=1/fac[i];
        }
        cin>>n>>m;
        for(int i=0;i<n;i++){
            cin>>s[i];
        }
        base[0]=1;
        base[1]=0;
        base[2]=finv[2];
        for(int i=3;i<=3e5;i++){
            if(i%2==1){
                base[i]=((base[i-1]-finv[i])%mod+mod)%mod;
            }else{
                base[i]=((base[i-1]+finv[i])%mod+mod)%mod;
            }
        }
        ll ans=0,cnt=0;
        // cnt计算有d多少个白点
        // ans为期望
        for(int i=0;i<n;i++){
            int temp=0;
            for(int j=0;j<m;j++){
                if(s[i][j]=='o'){
                    cnt++;
                    temp++;
                }else{
                    temp=0;
                }
                ans=(ans+base[temp])%mod;
            }
        }
        for(int j=0;j<m;j++){
            int temp=0;
            for(int i=0;i<n;i++){
                if(s[i][j]=='o'){
                    temp++;
                }else{
                    temp=0;
                }
                ans=(ans+base[temp])%mod;
            }
        }
        ans=ans*fac[cnt]%mod;
        printf("%lld
    ",ans);
        return 0;
    }
    
    
    
    卷也卷不过,躺又躺不平
  • 相关阅读:
    jackson自动将东八区时间转成标准时间
    开发项目和所用时间 感想
    自我介绍
    后缀数组模板
    lucas模板
    后缀数组da3模板
    cf#366....
    第1月2周1天
    第1月2周2天
    第1月1周1天
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/14658810.html
Copyright © 2020-2023  润新知