打工
来源:互联网 发布:maxdos 网络启动版 编辑:程序博客网 时间:2024/04/28 07:27
Input
第一行,一个整数N表示参赛人数。
第二行,N个整数,表示询问的分队方式的序列。
Output
一行,一个整数表示这种方式会在第几天被采用。答案对1,000,007取模。
Sample Input
3
1 2 2
Sample Output
4
Data Constraint
对于100%的数据,N ≤ 10000 , 数据保证询问的数列是一个有效的序列。
Hint
比赛各天的分队情况如下:
第一天:1,1,1
第二天:1,1,2
第三天:1,2,1
第四天:1,2,2
第五天:1,2,3
The Solution
首先注意到一个简单的性质,
一个数 x 要出现在序列里,必须要
在它前面的位置出现 x-1。
可以注意到,一个序列中如果要出现 k 这个数,那么在他之前的
位置 1~k-1 必定都出现过,这样构造出的序列才是合法的。
举个例子 1,2,2,2….3….1,2,1,2….3
然后我们可以设f[i][j][0..1]表示前i个数,最大的数是j,
0表示 < j这个数,1表示 = 这个数。
普通转移很显然,f[i]只与f[i-1],f[i]只与f[i+1]有关,所以我们可以用滚动数组。
从后往前,考虑每一个位置,与原序列完全符合,或字典序比原序列小
那么方案数显然是
z表示滚动0..1
计算方案数的式子长度为i,
写出来类似
这条式子很明显
因为你放一个数设为k,那么前面就有1~k的那么多个位置,再放入小于k的数的方案数显然为上述式子。
考虑 f[i]如何由 f[i-1]推来。当前这一位的后一位放 k 那么当前这
位就有 k 种放法;后一位放 k+1,就只有一种放法。
可以枚举最大值k
时间复杂度:O(N^2)
CODE
#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#define fo(i,a,b) for (int i=a;i<=b;i++)#define N 10005#define mo 1000007using namespace std;int n,a[N];int f[2][N][2],ans=0;// qian i ge shu zui da de shu shi j//0 < 1 =typedef long long ll;int main(){ freopen("data.in","r",stdin); scanf("%d",&n); fo(i,1,n) scanf("%d",&a[i]); f[0][1][1] = 1; int p=0,q=1;//o u int mx = 1; fo(i,1,n) { q = 1 - p; mx = max(mx,a[i]); fo(j,1,i) { f[q][j][1] = 0; int tmp = max(0,j-a[i]+1) , t = min(j,a[i]-1); f[q][j][0] =(f[p][j][0] * (ll)tmp + (f[p][j][0]+f[p][j][1]) * (ll)t + f[p][j-1][0]) % mo; if (j < a[i]) f[q][j][0] += f[p][j-1][1]; } f[q][mx][1] = 1; p = q; } fo(i,1,n) ans = ((ll)ans + f[p][i][1] + f[p][i][0])%mo; printf("%d\n",ans); return 0;}
- 打工
- 打工
- 打工
- 打工?
- 打工
- 打工
- 打工人生
- 打工联盟
- 打工曲
- IT打工
- 外出打工
- 打工的
- 打工去
- 打工心酸
- 打工者
- 打工vahnzjkl
- 【JZOJ1282】打工
- 【JZOJ4806】打工
- noip2010 关押罪犯 二分答案+二分图判断
- nginx和uwsgi配置
- Markdown输入数学公式
- 浙大 PAT b1024
- BFS_DFS深度广度优先C++实现。
- 打工
- android 通过Service和Receiver来监听网络状态
- TankWar 单机(JAVA版) 提前优化 图形化
- Lovelive 大正风格Lightroom调色思路
- wifi已通过硬件开关禁用
- malloc函数
- Android生成与正式签名对应的debug签名
- hdoj1325-Is It A Tree?
- IPhone导入还原手机通讯录