Xiangtan Invitation Contest 2017 - J Similar Subsequence(DP)

For given sequence A = (a1, a2, . . . , an), a sequence S = (s1, s2, . . . , sn) has shape A 

if and only if:• si = min{si, si+1, . . . , sn} for all ai = 0;• si = max{si, si+1, . . . , sn} for all ai = 1.

Given sequence B = (b1, b2, . . . , bm), Bobo would like to know the number of subsequences of length n whichhave shape A modulo (109 + 7).


分析:f[i,j,x,y]表示当前匹配到a的第i个位置,b的第j个位置,最大值为x,最小值为y的方案数,那么下一个决策就是f[i+1,j',x',y'] 其中j' > j且b[j] ∈[x,y],注意到x 和 y中一定有一个等于b[j],这样可以把状态精简为f[i,j,k],k表示最大值或最小值,此时如果暴力转移复杂度是n*m^3,可以用树状数组优化到n*m^2*log(m).


#include 
#define N 100005
#define MOD 1000000007
using namespace std;
typedef long long ll;
int n,m,a[25],b[505],f[25][505][505],p[25][505][505];
bool could(int i,int j,int k)
{
    if(a[i]) return b[j] >= k;
    else return b[j] <= k;
}
void Insert(int i,int j,int k,int x)
{
    while(k <= m)
    {
        p[i][j][k] += x;
        p[i][j][k] %= MOD;
        k += k & (-k);
    }
}
int Find(int i,int j,int k)
{
    int ans = 0;
    while(k)
    {
        ans = ans + p[i][j][k];
        ans %= MOD;
        k -= k & (-k);
    }
    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&m) != EOF)
    {
        memset(p,0,sizeof(p));
        memset(f,0,sizeof(f));
        for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
        for(int i = 1;i <= m;i++) scanf("%d",&b[i]);
        for(int j = m;j;j--)
        {
            for(int i = n;i;i--)
             for(int k = 1;k <= m;k++)
              if(could(i,j,k))
              {
                  int l = min(k,b[j]),r = max(k,b[j]);
                  int c = a[i+1] ? l : r;
                  if(i == n) f[i][j][k] = 1;
                  else f[i][j][k] = (Find(i+1,c,r) - Find(i+1,c,l-1) + MOD) % MOD;
              }
            for(int i = n;i;i--)
             for(int k = 1;k <= m;k++)
              if(could(i,j,k)) Insert(i,k,b[j],f[i][j][k]);
        }
        int ans = 0;
        for(int j = 1;j <= m;j++)
        {
            if(a[1]) ans = (ans + f[1][j][1]) % MOD;
            else ans = (ans + f[1][j][m]) % MOD;
        }
        printf("%d\n", ans);
    }
}


你可能感兴趣的:(ACM,好题,不会做,DP动态规划)