A

题意

给一个字符串,由a,b,c字母和?组成。 ?可以填成a,b,c中的一个。求是否存在一种填法使得:字符串不存在任何相邻位置的字母相同。存在则输出填充后的字符串,不存在输出-1

思路

对于任何一个位置,只有两个邻居,但是有三种填法,所以说每个问号必定可以合法填充。按规则填完后检测一下就好了。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=1e5+5;

char s[MAX];
bool vis[3];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%s",s);
        int len=strlen(s);
        for(int i=1; i<len-1; i++)
        {
            if(s[i]=='?')
            {
                if(s[i-1]!='?')
                    vis[s[i-1]-'a']=1;
                if(s[i+1]!='?')
                    vis[s[i+1]-'a']=1;
                for(int j=0; j<3; j++)
                    if(!vis[j])
                    {
                        s[i]=j+'a';
                        break;
                    }
                memset(vis,0,sizeof vis);
            }
        }
        if(s[0]=='?')
            s[0]=((len>1?s[1]:'a')-'a'+1)%3+'a';
        if(s[len-1]=='?')
            s[len-1]=((len>1?s[len-2]:'a')-'a'+1)%3+'a';
        bool flag=1;
        for(int i=1;i<len;i++)
            if(s[i]==s[i-1])
            {
                flag=0;
                break;
            }
        if(flag)
            printf("%s\n",s);
        else
            printf("-1\n");
    }
}

B

题意

给定1-n的一个排列,求对于1-n的每个m,是否存在一个区间使得1-m所有数均在这个区间中。

思路

记录一下数i的位置,记为pos[i]。然后递推处理,记max1-i中出现的最大位置,min为最小位置。则可以保证前i个数一定出现在[min,max]之间。若此时max-min+1==i即区间长度为i则说明前i个数均在此区间内,即长为i的区间存在。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=2e5+5;

int pos[MAX];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,x;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d",&x),pos[x]=i;
        printf("1");
        int minn=pos[1],maxx=pos[1];
        for(int i=2; i<=n; i++)
        {
            minn=min(minn,pos[i]);
            maxx=max(maxx,pos[i]);
            if(maxx-minn+1==i)
                printf("1");
            else
                printf("0");
        }
        printf("\n");
    }
}

C

题意

比赛发牌子,给出n个队伍的过题数,发g个金牌,s个银牌,b个铜牌,使得g,s,b满足以下要求:

  • g,s,b > 0
  • g < sg < b
  • 金牌队伍过题数必须严格大于银牌队伍
  • 银牌队伍过题数必须严格大于铜牌队伍
  • 铜牌队伍过题数必须严格大于无牌队伍
  • 总奖牌数小于队伍数量一般(向下取整),即g+s+b < n/2

思路

贪心依次推,在满足1,3条件的前提下g尽可能少,在满足1,2,4条件的前提下s尽可能少,b取满足1,5条件的剩余结果,若都能满足则有解,否则无解。

代码

#include<bits/stdc++.h>

using namespace std;
const int MAX=4e5+5;

int a[MAX];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        int g=0,s=0,b=0,p=0;
        int ed=n/2;
        while(a[ed]==a[ed-1]&&ed>0)ed--;
        while(p<ed&&a[p]==a[p+1])p++;
        g=p=p+1;
        while(p<ed&&(a[p]==a[p+1]||p+1<=g*2))p++;
        s=p-g+1;
        b=ed-p-1;
        if(g==0||s==0||b==0||g>=s||g>=b)
            g=s=b=0;
        printf("%d %d %d\n",g,s,b);
    }
}

D

题意

0,1,2,3这四种数,分别有a,b,c,d个,求如何排列使得序列任意相邻的两个数差距,即abs(a[i]-a[i+1]),不超过1

思路

很显然0必须和1相邻,3必须和2相邻,所以至少需要a1d2,所以b-=a,c-=d,然后看此时的c,d之差距是否不超过1,若是则有解,输出,否则无解。 再特判一下0,1数量全为0或者2,3数量全为0的情况即可。

代码

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int a,b,c,d;
    scanf("%d%d%d%d",&a,&b,&c,&d);
    int bb=b-a;
    int cc=c-d;
    if(a==b&&a==0&&d-c==1)
    {
        printf("YES\n3 ");
        for(int i=0;i<c;i++)
            printf("2 3 ");
        printf("\n");
        return 0;
    }
    if(a-b==1&&c==d&&d==0)
    {
        printf("YES\n");
        for(int i=0;i<b;i++)
            printf("0 1 ");
        printf("0\n");
        return 0;
    }
    if(bb<0||cc<0||abs(bb-cc)>1)
    {
        printf("NO\n");
        return 0;
    }
    printf("YES\n");
    if(bb==cc)
    {
        for(int i=0;i<a;i++)
            printf("0 1 ");
        for(int i=0;i<bb;i++)
            printf("2 1 ");
        for(int i=0;i<d;i++)
            printf("2 3 ");
    }
    if(bb-cc==1)
    {
        printf("1 ");
        for(int i=0;i<a;i++)
            printf("0 1 ");
        for(int i=0;i<bb-1;i++)
            printf("2 1 ");
        for(int i=0;i<d;i++)
            printf("2 3 ");
    }
    if(cc-bb==1)
    {
        for(int i=0;i<a;i++)
            printf("0 1 ");
        for(int i=0;i<bb;i++)
            printf("2 1 ");
        for(int i=0;i<d;i++)
            printf("2 3 ");
        printf("2 ");
    }
    printf("\n");
    return 0;
}

E

题意

一个人有n个魔镜,第i个魔镜有pi的概率说这个人好看。现在从第一个魔镜开始问起,每天问一个,若魔镜说好看则第二天继续问下一个,若说不好看则第二天从第一个魔镜重新开始问起。若第n个魔镜说好看则这个人会变开心。求让他变开心所需要的天数的期望,输出对998244353取模。

思路

求期望,马尔可夫链,由出边连接节点向本节点转移。可得如下模型。

dp[i]表示由第i个魔镜开始询问到达最终状态的期望天数。
最后一个魔镜也需要询问,所以设最终状态为dp[n+1]=0。即由最终状态转移到最终状态期望天数为0
最终答案即为dp[1]由此模型推导得出
\[dp[1]=dp[2]*p+dp[1]*(1-p_1)+1\\\Rightarrow dp[1]=dp[2]+\frac 1p_1 \qquad(1)\\dp[2]=dp[3]*p_2+dp[1]*(1-p_2)+1\\代入(1)\Rightarrow dp[1]=dp[3]+\frac 1p_2+\frac 1{p_1p_2}\]
可得规律
\[dp[1]=dp[n+1]+\frac 1p_n+\frac1{p_np_{n-1}}+\cdots+\frac 1{p_n \cdots p_1}\\\Downarrow\\dp[1]=\frac {p_{n-1}\cdots p_1+p_{n-2}\cdots p_1+\cdots+p_1+1}{p_1\cdots p_n}\]
计算出此式即可。有除法取模,所以要求逆元。模数为质数,用费马小定理。乘一个1ll提升字节数防止溢出。

代码

#include<bits/stdc++.h>

using namespace std;
const int mod=998244353;

int qpow(int a,int k)
{
    int res=1;
    for(;k;k>>=1)
    {
        if(k&1)
            res=1ll*res*a%mod;
        a=1ll*a*a%mod;
    }
    return res%mod;
}

int inv(int x){return qpow(x,mod-2);}

int main()
{
    int a=0,b=1,n,inv100=inv(100);
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int x;
        scanf("%d",&x);
        x=1ll*x*inv100%mod;
        a=(a+b)%mod;
        b=1ll*b*x%mod;
    }
    printf("%d\n",(1ll*a*inv(b)%mod+mod)%mod);
}
02-14 04:39