URAL1696 Salary for Robots

题目戳这里
最长下降子序列单调队列求法。
\(f_{i,j,k}\)表示考虑前\(i\)个数,\(g_1 = j,g_2 = k\)的方案数。转移:
$$f_{i,j,k} = \sum_{p = k+1}{j}f_{i-1,p,k}+\sum_{p=0}kf_{i-1,j,p}$$
二维前缀和优化。复杂度\(O(NK^2)\)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std;

const int maxk = 201;
int f[2][maxk][maxk],N,K,rhl,ans;

int main()
{
	freopen("1696.in","r",stdin);
	freopen("1696.out","w",stdout);
	scanf("%d %d %d",&N,&K,&rhl);
	for (int i = 1;i <= K;++i) f[1][i][0] = 1;
	for (int p = 2,now = 0,last = 1,inc;p <= N;++p,swap(now,last))
	{
		for (int i = 1;i <= K;++i)
		{
			for (int j = i-1;j >= 0;--j)
			{
				f[last][i][j] += f[last][i][j+1];
				if (f[last][i][j] >= rhl) f[last][i][j] -= rhl;
			}
			for (int j = 0;j < i;++j)
			{
				f[last][i][j] += f[last][i-1][j];
				if (f[last][i][j] >= rhl) f[last][i][j] -= rhl;
			}
		}
		memset(f[now],0,sizeof f[now]);		
		for (int i = 1;i <= K;++i)
			for (int j = 0;j < i;++j)
			{
				f[now][i][j] = f[last][i][j]-f[last][j][j]-f[last][i][j+1]+f[last][j][j+1];
				while (f[now][i][j] >= rhl) f[now][i][j] -= rhl;
				while (f[now][i][j] < 0) f[now][i][j] += rhl;
				if (j)
				{
					inc = f[last][i][0]-f[last][i-1][0]-f[last][i][j+1]+f[last][i-1][j+1];
					while (inc >= rhl) inc -= rhl; while (inc < 0) inc += rhl;
					f[now][i][j] += inc; if (f[now][i][j] >= rhl) f[now][i][j] -= rhl;
				}
			}
	}
	for (int i = 1;i <= K;++i)
		for (int j = 0;j < i;++j)
		{
			ans += f[N&1][i][j];
			if (ans >= rhl) ans -= rhl;
		}
	printf("%d\n",ans+1);
	fclose(stdin); fclose(stdout);
	return 0;
}

posted @ 2017-02-15 23:30  lmxyy  阅读(284)  评论(0编辑  收藏