B - Symmetric Matrix
思路:将矩阵转换成图的形式,然后推公式。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define pii pair<int, int> #define y1 skldjfskldjg #define y2 skldfjsklejg using namespace std; const int N = 1e5 + 7; const int M = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; LL dp[N], sum[N]; int mod, n; LL fastPow(LL a, LL b) { LL ans = 1; while(b) { if(b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } void init() { dp[1] = 0; dp[2] = 1; dp[0] = 1; for(int i = 3; i <= n; i++) { sum[i] = (i - 1) * sum[i - 1] % mod + (1ll * (i - 1) * (i - 2) / 2) % mod * dp[i - 3] % mod; if(sum[i] >= mod) sum[i] -= mod; dp[i] = (i - 1) * dp[i - 2] % mod + sum[i]; if(dp[i] >= mod) dp[i] -= mod; } } int main() { while(scanf("%d%d", &n, &mod) != EOF) { init(); printf("%lld\n", dp[n]); } return 0; } /* 3 1000000000 100000 1000000000 507109376 */
E - Removal
题目大意:给你 n 个数, 每个数在1 - k 之间,现在让你删除 m 个数,问你最后有多少种序列。
思路:存在重复的问题,对于同一个序列我们只记录最靠前的一个,我们用nx[ i ][ j ]表示 i 后边第一个j 的位置。
可以得到dp方程: 每一个dp[ i ][ j ] 可以转移到 dp[ nx[ i ][ k ] ][ j + nx[ i ][ k ] - i - 1]
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define pii pair<int, int> #define y1 skldjfskldjg #define y2 skldfjsklejg using namespace std; const int N = 1e5 + 7; const int M = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 +7; int n, m, up, a[N], mp[11], nx[N][11], dp[N][11]; void init() { memset(mp, 0, sizeof(mp)); for(int i = 0; i <= n; i++) for(int j = 0; j <= 10; j++) dp[i][j] = nx[i][j] = 0; } void add(int &a, int b) { a += b; if(a >= mod) a -= mod; } int main() { while(scanf("%d%d%d", &n, &m, &up) != EOF) { init(); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for(int i = n; i >= 0; i--) { for(int j = 1; j <= up; j++) { nx[i][j] = mp[j]; } mp[a[i]] = i; } dp[0][0] = 1; for(int i = 0; i < n; i++) { for(int j = 0; j <= m; j++) { if(!dp[i][j]) continue; for(int k = 1; k <= up; k++) { int pos = nx[i][k]; if(pos && j + pos - i - 1 <= m) { add(dp[pos][j + pos - i - 1], dp[i][j]); } } } } int ans = 0; for(int i = 1; i <= n; i++) { int j = n - i; if(j <= m) add(ans, dp[i][m - j]); } printf("%d\n", ans); } return 0; } /* 3 2 2 1 2 1 4 2 2 1 2 1 2 */