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\n",cnt);

    }
    return 0;
}
 

B题

大意

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

\(1\le a,b\le9,1\le c\le \min(a,b)\)

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

思路

构造方法有很多种

我是构造成\(x=2^{k1}\times 10^{c-1}\),\(y=3^{k2}\times 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\n",ans1,ans2);

    }
    return 0;
}
 

C题

大意

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

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

要你找到一个最小的位置\(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(n\le2e5)\)的字符串,且只能使用前\(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\times m(n\times m\le3e5)\)的矩阵

其中有黑点和白点

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

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

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

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

思路

本质上是个概率论问题qwq

首先设有\(cnt\)个白点,假设期望为\(e\),那么答案就是\(2^{cnt}\times 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\n",ans);
    return 0;
}


posted @ 2021-04-14 16:58  hunxuewangzi  阅读(53)  评论(0编辑  收藏  举报