zoukankan      html  css  js  c++  java
  • 【控制dp】Count Subsequences【Codechef】

    中文题面

    https://s3.amazonaws.com/codechef_shared/download/translated/CK101TST/mandarin/CSUBSQ.pdf

    该问题乍一看很容易想到dp。

    dp的话,就是按模数分类计数;即f[i][x]表示扫描到i时子序列和的模为x的方案数,转移就不说了。

    但是题目限制端点$i_{l}-i_{1}  geq w$,这时候要对dp进行控制,可以用分治算法

    考虑区间[l,r],区间中点为mid,那么可以枚举区间末端点$i_{l}$,并使其大于mid,再在mid左端选一些点,从而达到控制端点的目的。

    然后分治即可。该题思路大致如此,具体看代码。

    分治加上dp的复杂度是On*k*logn

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    const int N=1e5+3,K=50+3;
    typedef long long ll;
    const int mod=1e9+7;
    
    int a[N];
    int k,w;
    ll ans;
    ll f[N][K],g[N][K];
    void solve(int l,int r)
    {
        if(r-l<w)
            return;
        if(l==r)
        {
            if(a[l]==0)
                ans=(ans+1)%mod;
            return;
        } 
        int mid= l+r>>1;
        memset(f[mid+1],0,sizeof f[mid+1]);
        memset(g[mid],0,sizeof g[mid]);
        f[mid+1][0]= g[mid][0]= 1;
        
        for(int i=mid;i>=l;i--)
            for(int x=0;x<k;x++)
                f[i][x]= (f[i+1][(x-a[i]+k)%k]+f[i+1][x])%mod;
                
        for(int i=mid+1;i<=r;i++)
            for(int x=0;x<k;x++)
                g[i][x]= (g[i-1][(x-a[i]+k)%k]+g[i-1][x])%mod;
        
        ll t1,t2;
        for(int i=r;i>=mid+1;i--)
        {
            if(i-l<w) break;
            for(int x=0;x<k;x++)
            {
                int y=(k-x)%k;
                
                t1=g[i][x]-g[i-1][x];
                
                if(i-w+1>mid) t2=f[l][y]- f[mid+1][y];
                else t2=f[l][y]-f[i-w+1][y];
                
                t1=(t1+mod)%mod;
                t2=(t2+mod)%mod;
                ans=(ans+t1*t2%mod)%mod;
            }
        }
        solve(l,mid);
        solve(mid+1,r);
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            int n;
            scanf("%d%d%d",&n,&k,&w);
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            ans=0;
            solve(1,n);
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    编程总结2
    编程总结3
    《秋季学期学习总结》
    《人生路上对我影响最大的三位老师》
    第八周编程总结
    第七周编程总结
    第六周编程总结
    第五周作业
    第四周编程总结
    第三周编程总结
  • 原文地址:https://www.cnblogs.com/mgnfcnt/p/10440781.html
Copyright © 2011-2022 走看看