Codeforces 588D Duff in Beach 【离散化 + dp】

题目链接:Codeforces 588D Duff in Beach

D. Duff in Beach
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
While Duff was resting in the beach, she accidentally found a strange array b0, b1, …, bl - 1 consisting of l positive integers. This array was strange because it was extremely long, but there was another (maybe shorter) array, a0, …, an - 1 that b can be build from a with formula: bi = ai mod n where a mod b denoted the remainder of dividing a by b.

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.
Since this number can be very large, she want to know it modulo 109 + 7.

Duff is not a programmer, and Malek is unavailable at the moment. So she asked for your help. Please tell her this number.

Input
The first line of input contains three integers, n, l and k (1 ≤ n, k, n × k ≤ 106 and 1 ≤ l ≤ 1018).

The second line contains n space separated integers, a0, a1, …, an - 1 (1 ≤ ai ≤ 109 for each 0 ≤ i ≤ n - 1).

Output
Print the answer modulo 1 000 000 007 in one line.

Examples
input
3 5 3
5 9 1
output
10
input
5 10 3
1 2 3 4 5
output
25
Note
In the first sample case, . So all such sequences are: , , , , , , , , and .

定义b[]的合法子序列:非降序,记子序列相邻元素在原序列中下标为i和j(i < j),要求i / n + 1 == j / n。
题意:给定n个数的序列a[],让你循环构造出长度为l的序列b[]。问序列b[]中合法的不同子序列个数。

思路:题目给出了n*k<=10^6,就一定有目的。。。我们先抛开l不说,我们构造出一个k段的a[]序列,记为c[]。
设置 dp[i][j] 为以第i段第j个元素为末尾的子序列数目,我们先不考虑长度为1的子序列,算的时候从第1段算起。段数从0计数。
初始化 dp[0][j]=1 ,转移显然有 dp[i][j]=nk=1dp[i1][k]c[k]<=c[j] 。为了保证 c[k]<=c[j] 先离散化。这样的话这道题已经可以做了,其实我们还可以简化一下。

同样先离散化(按权值升序,下标升序),当我们处理到第i段第j个元素时,在它前面的所有比它小的元素都已经处理完了,对于此时的 dp[i][j] ,我们只需要累加所有的 dp[i1][] 即可(没处理的值肯定是0),这样的话,每次 dp[i][j] 的求解只依赖于当前dp[i-1]里面的所有值。我们可以优化掉第二维有 dp[i]=dp[i]+dp[i1]

考虑以b[p]元素结尾的方案:(p < l && p / n > 0)我们要从第1段开始算
已经求出的 dp[p/i1] 自然是前面的所有合法方案,我们只需要统计出后面有多少段包含元素a[p%n] (我们可以选择其中一个作为末尾段)即可。方案数为 (合法段数 * dp[p/i-1])。

AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MOD = 1e9 + 7;
const int MAXN = 1e6 + 10;
void add(LL &x, LL y) { x += y; x %= MOD; }
pii a[MAXN];
int b[MAXN];
LL dp[MAXN];
int main()
{
    int n, k; LL l;
    while(scanf("%d%lld%d", &n, &l, &k) != EOF) {
        for(int i = 0; i < n; i++) {
            scanf("%d", &b[i]);
        }
        int m = n * k;
        for(int i = 0; i < m; i++) {
            a[i].fi = b[i%n];
            a[i].se = i; dp[i] = 0;
        }
        sort(a, a+m); LL ans = l % MOD;
        int yu = l % n;
        for(int i = 0; i < m; i++) {
            int id = a[i].se;
            if(id < n) {
                add(dp[id/n], 1);
            }
            else {
                add(dp[id/n], dp[id/n-1]);
            }
            if(id < l && id >= n) {
                LL cnt = (l - 1) / n - id / n + 1;
                if(yu && (id % n) > yu-1) {
                    cnt--;
                }
                //cout << cnt << endl;
                add(ans, cnt%MOD*dp[id/n-1]%MOD);
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(Codeforces 588D Duff in Beach 【离散化 + dp】)