1. 程式人生 > 其它 >9.29模考

9.29模考

T1 打表(table)

Sol
所謂最優不最優都是假的。因為顯然當一個取法最優的時候,其對立面就是最不優的,而每次選擇優和不優是等概率的,所以實際上每個數都是等概選取,答案就是所有數與原數的差的絕對值之和除\(2^k\)
Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=1000000007,maxn=1000010;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
    return f?x:-x;
}
inline int ksm(int x,int mi)
{
    int ans=1;
    while(mi)
    {
        if(mi&1)ans=ans*x%p;
        x=x*x%p;mi>>=1;
    }
    return ans;
}
int n,k,a[maxn];
signed main()
{
    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);
    k=read();n=read();
    int m=1<<k;
    for(int i=0;i<m;i++)a[i]=read();
    int sum=0;
    for(int i=0;i<m;i++)
    {
        sum+=abs(a[i]-a[n]);
    }
    sum%=p;
    printf("%lld\n",sum*ksm(m,p-2)%p);
    return 0;
}

T2 蛇(snake)

Sol
因為只有兩行,所以蛇的軌跡一定可以拆分成三部分:向前然後調頭、s形扭曲前進、向後然後調頭。
向前調頭和向後調頭的部分可以雜湊解決,而中間的s形部分考慮DP。
\(dp[i][j][k][0]、dp[i][j][k][1]\)分別表示到\(i,j\)的位置蛇到\(k\)位置時,有/沒有變道的方案數。
那麼顯然有

\[dp[i][j][k][0]+=dp[i][j-1][k-1][0]+dp[i][j-1][k-1][1] \]\[dp[i][j][k][1]+=dp[i^1][j][k-1][0] \]

前後的雜湊部分要注意方向即可。
由於蛇的方向不固定,所以要反向在跑一遍。但是上下沒有方向,所以當蛇長為\(1\)

\(2\)時需要特殊處理,減去重複部分。
不知道為什麼掛了的code

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef unsigned long long ull;
const int maxn=2010,p=1000000007;
int dp[2][maxn][maxn<<1][2];//行、列、路徑長、是否換行 
ull hash1[2][2][maxn],hash2[maxn];
ull bw[maxn];
ull gethash1(int x,bool flag,int st,int t)
{
    if(flag)return hash1[x][flag][t]-hash1[x][flag][st+1]*bw[st-t+1];
    return hash1[x][flag][t]-hash1[x][flag][st-1]*bw[t-st+1];
}
ull gethash2(int st,int t)
{
    return hash2[t]-hash2[st-1]*bw[t-st+1];
}//雜湊 
int n,l,ans;
char s[maxn];
int a[2][maxn],snk[maxn];
inline void pre()
{
    for(int i=0;i<2;i++)
    {
        for(int j=1;j<=n;j++)
        {
            hash1[i][0][j]=hash1[i][0][j-1]*107+a[i][j];
        }
    }
    for(int i=0;i<2;i++)
    {
        for(int j=n;j>=1;j--)
        {
            hash1[i][1][j]=hash1[i][1][j+1]*107+a[i][j];
        }
    }
    return;
}
inline void work()
{
    pre();//預處理雜湊 
    for(int i=0;i<2;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]==snk[1])dp[i][j][1][0]=1;//第一段預處理 
            for(int k=2;k<=j;k++)
            {
                if(k<<1>l)break;
                if(gethash1(i,0,j-k+1,j)==gethash2(1,k)&&gethash1(i^1,1,j,j-k+1)==gethash2(k+1,k<<1))dp[i][j][k<<1][1]=1;
            }
        }
    }
    for(int k=1;k<=l;k++)
    {
        for(int i=0;i<2;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(a[i][j]!=snk[k])continue;
                dp[i][j][k][0]=(dp[i][j][k][0]+dp[i][j-1][k-1][0]+dp[i][j-1][k-1][1])%p;//直走 
                dp[i][j][k][1]=(dp[i^1][j][k-1][0]+dp[i][j][k][1])%p;//蛇形轉向 
            }
        }
    }
    for(int i=0;i<2;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=0;k<=l;k++)
            {
                if((l-k)%2!=0)continue;
                int le=(l-k)>>1;
                if(le==1)continue;
                if(j+le>n)continue;
                if(k==l||gethash1(i,0,j+1,j+le)==gethash2(k+1,k+le)&&gethash1(i^1,1,j+le,j+1)==gethash2(k+le+1,l))
                {
                    ans=(ans+dp[i][j][k][0]+dp[i][j][k][1])%p;
                }
            }
        }
    }
    return;
}
signed main()
{
    freopen("snake.in","r",stdin);
    freopen("snake.out","w",stdout);
    scanf("%s",s+1);n=strlen(s+1);
    for(int i=1;i<=n;i++)a[0][i]=s[i]-'a';
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)a[1][i]=s[i]-'a';
    scanf("%s",s+1);l=strlen(s+1);
    bw[0]=1;
    for(int i=1;i<=l;i++)
    {
        snk[i]=s[i]-'a';
        hash2[i]=hash2[i-1]*107+snk[i];
        bw[i]=bw[i-1]*107;
    }
    work();
    reverse(a[0]+1,a[0]+n+1);
    reverse(a[1]+1,a[1]+n+1);
    memset(dp,0,sizeof(dp));
    work();
    if(l==1)
    {
        for(int i=0;i<2;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(a[i][j]==snk[1])ans--;
            }
        }
    }
    if(l==2)
    {
        for(int i=0;i<2;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(a[i][j]==snk[1]&&a[i^1][j]==snk[2])ans--;
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}