打工

来源:互联网 发布:投标书编制软件 编辑:程序博客网 时间:2024/06/10 21:23

题目

这里写图片描述
样例输入:
第一行,一个整数N表示参赛人数。
第二行,N个整数,表示询问的分队方式的序列。
3
1 2 2

样例输出:
一行,一个整数表示这种方式会在第几天被采用。答案对1,000,007取模。

数据范围:
对于100%的数据,N ≤ 10000 , 数据保证询问的数列是一个有效的序列。
详细情况见下表。
这里写图片描述


剖解题目

。。。。。


思路

这题好坑啊。。。。。
比赛时想了一会儿,看了看30分好拿。
发现可以dp,但看到n<=10000,就觉得n^2肯定过不了,想了半天又觉得我的dp似乎是n^3,就没有动手打。
然后交了个暴力水了30分。QwQ.


解法

30%:暴力!
其他部分分就不说了。
100%:有顺推与逆推。
我们发现第i位后的方案数至于第i位后的长度以及前i位的最大值有关。
逆推(粗略提一下,我没打):设f[i,j]表示前i位已经匹配完,且最大的ai是j的方案数,那么就有f[i,j]=f[i+1,j]*j+f[i+1,j+1];
初始化是f[n][i]=1;

顺推:差不多,f[i][j]=f[i-1][j]*j+f[i-1][j-1];然后由于每一位都有a[i]的限制,不需要全部处理。每次dp完i,就对f[i][max(1~i-1)]+=a[i]-1;就不需要初始化了。

注意:由于空间限制,一般是要滚动f的第一维,但我偷了点懒,将所有计算都转化为longlong的形态,就没有开滚动。


代码

#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define fo(i,a,b) for(int i=a;i<=b;i++)#define down(i,a,b) for(int i=a;i>=b;i--)#define ll long longusing namespace std;const int maxn=10005,mo=1e6+7;int f[maxn][maxn],n,a[maxn],c[maxn];int main(){//  freopen("T.in","r",stdin);    scanf("%d",&n);    fo(i,1,n) {        scanf("%d",&a[i]);        c[i]=max(a[i],c[i-1]);        //f[n][i]=1;    }    int ans=0;    fo(i,2,n){        fo(j,1,i) f[i][j]=((ll)f[i-1][j]*(ll)j+(ll)f[i-1][j-1])%mo;        f[i][c[i-1]]=((ll)f[i][c[i-1]]+(ll)a[i]-1)%mo;    }    fo(i,1,n) ans=((ll)ans+(ll)f[n][i])%mo;    printf("%d",ans+1);}

这里写图片描述

0 0
原创粉丝点击