zoukankan      html  css  js  c++  java
  • luogu4187

    P4187 [USACO18JAN]Stamp Painting

    样例

    input
    3 2 2
    output
    6

    input
    6 10 5
    output
    190

    sol:首先可以发现,对于合法的序列,只要有一串至少连续K个相同的就可以了,其他没有限制

    这当然是可以dp辣

    dp[i][j]表示前i位没有,当前有j个连续相同,前面没有出现连续K个相同 

    统计答案的时候就是∑i={K,n} dp[i][K]*Ksm(m,n-i)

    转移挺容易的

    dp[1][1]=m

    dp[i][1]=(m-1)*∑j={1,K-1} dp[i-1][j]

    dp[i][j=(2~K)] = dp[i-1][j-1]

    但是就这样裸的暴力肯定是n2

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const ll Mod=1000000007;
    const int N=1005;
    int n,m,K;
    ll dp[N][N]; //dp[i]表示前i位没有,当前有j个连续相同,前面没有出现连续K个相同 
    inline void Ad(ll &x,ll y)
    {
        x+=y;
        x-=(x>=Mod)?Mod:0;
    }
    inline ll Ksm(ll x,ll y)
    {
        ll ans=1;
        while(y)
        {
            if(y&1) ans=ans*x%Mod;
            x=x*x%Mod;
            y>>=1;
        }
        return ans;
    }
    int main()
    {
        freopen("data.in","r",stdin);
        freopen("baoli.out","w",stdout);
        int i,j;
        ll ans=0;
        R(n); R(m); R(K);
        dp[1][1]=m;
        for(i=2;i<=n;i++)
        {
            for(j=1;j<=(K-1)&&j<=(i-1);j++) Ad(dp[i][1],dp[i-1][j]*(m-1)%Mod);
            for(j=2;j<=K&&j<=i;j++)
            {
                dp[i][j]=dp[i-1][j-1];
            }
        }
    //    for(i=1;i<=n;i++)
    //    {
    //        for(j=1;j<=K;j++) W(dp[i][j]);
    //        puts("");
    //    }
        for(i=K;i<=n;i++) Ad(ans,dp[i][K]*Ksm(m,n-i)%Mod);
        Wl(ans);
        return 0;
    }
    /*
    input
    3 2 2
    output
    6
    */
    View Code

    然后面临的问题就是怎么优化这个dp,容易发现其实每次除了第一位,另外都是不变的(向右移一位而已),所以只要更新第一位的值可以了

    有这样两个队列

                    1 2 3 4 5              Head=10 Tail=14
                 x 1 2 3 4                 Head=9 Tail=13

    发现了吗,只要搞一个队列,每次Head-1,Tail-1就会向左移一位,那个红色的x就是要更新的值了

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const ll Mod=1000000007;
    const int N=1000005;
    int n,m,K;
    ll dp[N]; //dp[j]表示前i位(已经滚掉)没有,当前有j个连续相同,前面没有出现连续K个相同
    ll Queue[N<<1];
    ll Bin[N];
    inline void Ad(ll &x,ll y)
    {
        x+=y;
        x-=(x>=Mod)?Mod:0;
        x+=(x<0)?Mod:0;
    }
    int main()
    {
        freopen("data.in","r",stdin);
        freopen("my.out","w",stdout);
        int i;
        ll Sum=0,ans=0;
        R(n); R(m); R(K);
        dp[1]=m; for(i=2;i<=K;i++) dp[i]=0;
        Sum=m;
        for(i=1;i<=K;i++) Queue[n+i]=dp[i];
        Bin[0]=1; for(i=1;i<=n;i++) Bin[i]=Bin[i-1]*m%Mod;
        int Head=n+1,Tail=n+K;
        Ad(ans,Queue[Tail]*Bin[n-1]%Mod);
        for(i=2;i<=n;i++)
        {
            Queue[Head-1]=(Sum-Queue[Tail]+Mod)*(m-1)%Mod;
            Ad(Sum,Queue[Head-1]);
            Ad(Sum,(-1)*Queue[Tail]);
            Head--;
            Tail--;
    //        for(int j=Head;j<=Tail;j++) W(Queue[j]);
    //        puts("");
            Ad(ans,Queue[Tail]*Bin[n-i]%Mod);
        }
        Wl(ans);
        return 0;
    }
    /*
    input
    3 2 2
    output
    6
    
    input
    6 10 5
    output
    190
    */
    /*
           1 2 3 4 5 Head=10 Tail=14
           1 2 3 4     Head=9 Tail=13
    */
    View Code

    Ps:最后附上对拍

    :loop
    make.exe
    luogu4187.exe
    baoli.exe
    fc my.out baoli.out
    if not errorlevel 1 goto loop
    pause
    goto loop
    pai
    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int Mod=1000;
    int main()
    {
        freopen("data.in","w",stdout);
        srand(time(NULL));
        int n,m,k;
        n=rand()%Mod+1;
        m=rand()%Mod+1;
        k=rand()%n+1;
        W(n); W(m); Wl(k);
        return 0;
    }
    make
  • 相关阅读:
    ActiveReport换页的判断(当设置了repeatstyle为OnPage)
    创建与删除SQL约束或字段约束。 http://www.cnblogs.com/hanguoji/archive/2006/11/17/563871.html
    在SQL Server 2005中实现表的行列转换
    ActiveReport,Detail隐藏的问题
    SQL Server identity列的操作方法
    「預り」の意味
    POJ 1595 Prime Cuts
    Hdu Graph’s Cycle Component
    POJ 3250 Bad Hair Day
    Hdu 1548 A strange lift(BFS)
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10693020.html
Copyright © 2011-2022 走看看