题目:http://codeforces.com/problemset/problem/588/D
题意:已知长度为n的数组a[0...n-1]和长度为l的数组b[0...l-1],并且b[i]=a[i%n],在b[0...l-1]中找有多少种特殊的序列其满足3个条件:
Duff is so curious, she wants to know the number of subsequences of b like bi1, bi2, ..., bix (0 ≤ i1 < i2 < ... < ix < l), such that:
- 1 ≤ x ≤ k
- For each 1 ≤ j ≤ x - 1,
- For each 1 ≤ j ≤ x - 1, bij ≤ bij + 1. i.e this subsequence is non-decreasing.
分析:记ss[i]为长度为i-1的方案数(从第一层开始的,即第一个元素的位置<n)。会用到的b[0...l-1]里面的元素最多有n*k个,将这些元素取出来,并标记位置,然后从小到大排序。那么枚举这n*k个元素,如果当前元素的标记的位置为id,那么以这个元素结尾的方案数为ss[id/n-1],因为已经排好序,上一层的方案对这个元素都是合法的,然后更新ss[id/n]。如果id<l,那么以当前元素结尾的方案数都可行,和当前序列类似的序列还有[l-(id+1)]/n个,加上去就行了。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = (1ll<<31);
const LL mod = 1000000007;
const int maxn = 1E6+7;
pair <int ,int > p[maxn];
int a[maxn];
LL dp,sum[maxn];
int main()
{
LL n,l,k,i,lim,id;
scanf("%lld%lld%lld",&n,&l,&k);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
lim=n*k;
for(i=0;i<lim;i++)
p[i]=make_pair(a[i%n],i);
sort(p,p+lim);
LL ans=0;
for(i=0;i<lim;i++)
{
id=p[i].second;
if(id<n)
dp=1;
else
dp=sum[id/n-1];
sum[id/n]=(sum[id/n]+dp)%mod;
if(id<l)
{
LL nums=(l-id+n-1)/n;
ans=(ans+nums%mod*dp)%mod;
}
}
printf("%lld\n",ans);
return 0;
}