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);
}
}