http://codeforces.com/contest/588/problem/D
感觉吧,这道题让我做,我应该是不会做的。。。
题目大意:给出n,L,K。表示数组的长度为n,数组b的长度为L,定义数组b[i]=a[i%n]。然后数组b的最长的lis为k,问能有几组<=k的lis
条件如下:
①序列长度>=1并且<=k
②序列在每一块长度为n的数组中只能选择一个数,且选择的必须是连续的块
③序列是不严格的单调递增
思路:主要是看这个人的http://m.blog.csdn.net/article/details?id=50589276
大致思路就是:定义dp[K][N](用dp[i][j]描述),表示目前lis的最长长度为i,到第j个数的时候lis总共有几个。然后求出lis以后再利用lis得到答案即可。
代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//看看会不会爆int! 或者绝对值问题。 #include <bits/stdc++.h> using namespace std; #define LL long long #define pb push_back #define mk make_pair #define fi first #define se second #define ALL(a) a.begin(), a.end() const int maxn = 1e6 + 5; const LL mod = 1e9 + 7; int n, K; LL l; pair<int, int> a[maxn]; int main(){ scanf("%d%lld%d", &n, &l, &K); for (int i = 0; i < n; i++){ int u; scanf("%d", &u); a[i] = mk(u, i); } sort(a, a + n); vector<vector<int> > dp(K, vector<int>(n)); for (int i = 0; i < n; i++) dp[0][i] = 1; for (int i = 1; i < K; i++){ int sum = 0; ///dp[i][j]表示目前长度为i,在位置j之前的所有的lis的和 ///首先,只以i和k转移,找到在一个周期内的 for (int j = 0, k = 0; j < n; j++){ while (k < n && a[k].first <= a[j].first) { sum = (sum + dp[i - 1][k++]) % mod; } dp[i][j] = sum; } } /* for (int i = 0; i < K; i++){ for (int j = 0; j < n; j++){ printf("%d ", dp[i][j]); } printf(" "); } */ LL ans = 0; for (int i = 0; i < K; i++){ for (int j = 0; j < n; j++){ ///有l/n段长,后面的这个条件表示最后一个周期能否取到 LL cnt = l / n + (a[j].second < l % n); if (cnt - i > 0){///这里表明块,一共有cnt个,能满足这个长度 ans += (cnt - i) % mod * dp[i][j] % mod; ans %= mod; } } } printf("%lld ", ans); return 0; }