来自学长的馈赠4
A. 活动投票
2MB内存!?红色的大字我都没看见,还以为他只是想考一个离散化,于是乎MLE爆0……不过如果我注意到了,我能保证做对吗?这是一个问题……
(1MB=1034KB, 1KB=1024B 1int=4B)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int maxn = 3e6 + 2; const ll mod = 1e9 + 7; const int INF = 0x7ffffff; int n, fairy, tale, num; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { n = read(); fairy = read(); num = 1; for(int i=2; i<=n; i++) { tale = read(); if(tale == fairy) num++; else num--; if(num == 0) { fairy = tale; num = 1; } } printf("%d", fairy); return 0; }
B. 大佬
和的期望等与期望的和,所以答案就是每天的期望*天数,每天的期望就是每个可能的m出现的概率*对应的w。这是我赛时唯一一个过的题,我本来居然还想跳过它,看来期望也没那么恐怖
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int maxn = 505; const ll mod = 1e9 + 7; const int INF = 0x7ffffff; int n, m, k, w[maxn], day; ll mud[maxn], inv[maxn], ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } ll qpow(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() { mud[1] = 1; for(int i=2; i<maxn; i++) mud[i] = mud[i-1]*i%mod; inv[maxn-1] = qpow(mud[maxn-1], mod-2); for(int i=maxn-1; i>=1; i--) { inv[i-1] = inv[i]*i%mod; } } ll C(ll n, ll m) { if(m > n) return 0; return mud[n]*inv[m]%mod*inv[n-m]%mod; } int main() { n = read(); m = read(); k = read(); for(int i=1; i<=m; i++) { w[i] = read(); } init(); day = n-k+1; ll fm = qpow(m, mod-2); for(int i=1; i<=m; i++) { ll kns = 0;//这一天的劳累值为i的概率 for(int j=1; j<=k; j++)//几位是i { kns = (kns+C(k, j)*qpow(fm, j)%mod*qpow((i-1)*fm%mod, k-j)%mod)%mod; } ans = (ans + w[i]*kns%mod) % mod; } ans = ans * day % mod; printf("%lld", ans); return 0; }
C. Dp搬运工3
考场上打完暴力之后自作聪明的想到了一个结论:字典序越大k越大,因此找到一个比k大的直接减就行
结果WA 6分,它能秒过大样例就很鬼触,一开始的暴力可以TLE 20 分……
f[i][j][k]表示当前填完了1~i的数,其中有j个填到了下标为i+1~n的位置(j当前无贡献)
这也相当于在区间1~i之间有j个空位(有j个数没有在它本来该呆的地方),k指的是在
区间1~i之间的贡献,还要去掉没有匹配的
1.若将i填到了下标i,则k+=i
2.若将i填到了下标小于i的位置,下标i的位置填入了小于i的数,则k+=2*i,j--
——i增大了,原来算在j里的数被纳入区间1~i(有一个数在之前的i+1上但是因为i变化了所以他被纳入区间了)
——前面j个空位有j个选择,后面被包括进来的数可能是原来算进j里的任意一个 *j*j
3.若将i填到了下标小于i的位置,下标i的位置填入了大于i的数,则k+=i
——在预设型dp中大于就相当于没填,34的有效部分原理都和2的原理相同,5就相当于没得选
4.若将i填到了下标大于i的位置,下标i的位置填入了小于i的数,则k+=i
5.若将i填到了下标大于i的位置,下标i的位置填入了大于i的数,则j++
最后再把134合并一下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int maxn = 60; const ll mod = 998244353; const int INF = 0x7ffffff; int n, K; ll f[maxn][maxn][maxn*maxn], ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { n = read(); K = read(); f[0][0][0] = 1; for(int i=1; i<=n; i++) { for(int j=0; j<=i; j++) { for(int k=0; k<=K; k++) { ll G = f[i-1][j][k]; f[i][j][min(k+i, K)] = (f[i][j][min(k+i, K)]+(2*j+1)*G%mod)%mod; f[i][j+1][k] = (f[i][j+1][k]+G)%mod; if(j) f[i][j-1][min(k+2*i, K)] = (f[i][j-1][min(k+2*i, K)]+j*j*G%mod)%mod; } } } ans = f[n][0][K]; for(int i=2; i<=n; i++) { ans = ans * i % mod; } printf("%lld", ans); return 0; }
时光花火,水月星辰