KEYENCE Programming Contest 2021

AB

签到

C

大力DP,f[i][j]表示走到当前位置的方案数,但问题是无法考虑没走过路径的未填位置。不过很好解决,向右走的时候实际方案=原方案数*3^(走过的列下侧的未填位置数),向下走的时候实际方案=原方案数*3^(走过的行右侧的未填位置数),这样可以处理掉所有的未填位置。

#include<bits/stdc++.h>
using namespace std;
const int N=5005,mod=998244353;
int n,m,k,pw[N],a[N][N],f[N][N],s[N][N],t[N][N];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=-1;
    pw[0]=1;for(int i=1;i<=5000;i++)pw[i]=3ll*pw[i-1]%mod;
    for(int i=1,x,y;i<=k;i++)
    {
        char c;scanf("%d%d %c",&x,&y,&c);
        if(c=='X')a[x][y]=0;
        else if(c=='R')a[x][y]=1;
        else a[x][y]=2;
    }
    for(int j=1;j<=m;j++)
    {
        for(int i=n;i;i--)s[i][j]=s[i+1][j]+(a[i][j]==-1);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j;j--)t[i][j]=t[i][j+1]+(a[i][j]==-1);
    }
    f[1][1]=1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        if(j>1)
        {
            if(!a[i][j-1]||a[i][j-1]==1)f[i][j]=(f[i][j]+1ll*f[i][j-1]*pw[s[i+1][j-1]])%mod;
            else if(a[i][j-1]==-1)f[i][j]=(f[i][j]+2ll*f[i][j-1]*pw[s[i+1][j-1]])%mod;
        }
        if(i>1)
        {
            if(!a[i-1][j]||a[i-1][j]==2)f[i][j]=(f[i][j]+1ll*f[i-1][j]*pw[t[i-1][j+1]])%mod;
            else if(a[i-1][j]==-1)f[i][j]=(f[i][j]+2ll*f[i-1][j]*pw[t[i-1][j+1]])%mod;
        }
    }
    if(a[n][m]==-1)f[n][m]=3ll*f[n][m]%mod;
    printf("%d",f[n][m]);
}
View Code

D

构造能力堪忧于是成功垫底……

很容易发现答案是2^n-1,但就是不会构造……

发现可以将2^(n-1)个人时的答案进行如下复制,假设一个答案是A,则可以复制成AA,AB,其中B与A完全不同,再加上A…AB…B就可达到目的

#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{
    scanf("%d",&n);
    printf("%d\n",(1<<n)-1);
    vector<string>a;
    for(int i=1;i<=n;i++)
    {
        vector<string>vec;
        string x="";
        for(int j=1;j<=(1<<i-1);j++)x+='A';
        for(int j=1;j<=(1<<i-1);j++)x+='B';
        vec.push_back(x);
        for(int j=0;j<a.size();j++)
        {
            vec.push_back(a[j]+a[j]);
            string s=a[j];
            for(int k=0;k<s.size();k++)s[k]=s[k]=='A'?'B':'A';
            vec.push_back(a[j]+s);
        }
        a=vec;
    }
    for(int i=0;i<a.size();i++)cout<<a[i]<<endl;
}
View Code

E

考完发现实际上就是DP,f[i][j][k]表示在区间[i,j],取了k个区间外的数的最大值,也是直接DP就行了

#include<bits/stdc++.h>
using namespace std;
const int N=405;
int n,a[N],f[N][N][N];
int dp(int l,int r,int m)
{
    int&ret=f[l][r][m];
    if(ret)return ret;
    int t=0;
    if(l>0||r<=n)
    {
        if(m<n-(r-l-1))
        {
            if(a[l]<a[r])t=max(t,dp(l,r+1,m+1));
            else t=max(t,dp(l-1,r,m+1));
        }
        if(m>=1&&l>=1)t=max(t,a[l]+dp(l-1,r,m-1));
        if(m>=1&&r<=n)t=max(t,a[r]+dp(l,r+1,m-1));
    }
    ret=t;
    return ret;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    a[0]=a[n+1]=-1;
    for(int i=0;i<=n;i++)cout<<dp(i,i+1,1)<<endl;
}
View Code

小号打的 rank=426 performance=1931 rating+=149

 

posted @ 2021-01-16 23:00  hfctf0210  阅读(386)  评论(0编辑  收藏  举报