【牛客IOI周赛17-普及组】
夹娃娃
https://ac.nowcoder.com/acm/contest/5881/A
A 夹娃娃
求一下前缀和,即可 回答询问。整体复杂度 。
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n, k, a[N]; int main() { scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); a[i] += a[i - 1]; } while(k--) { int l, r; scanf("%d%d", &l, &r); printf("%d\n", a[r] - a[l - 1]); } return 0; }
B 莫的难题
- 求
利用公式 可递推求出。 - 求第 小的数。
先列一下从小到大的几个数:
显然和进制有关,我们将 转化为 。
那么数字序列即为:
这样就比较显然了:
① 位数为 的数字共有 个。
② 对于位数相同的这些数,即为所对应的五进制数。
因此可以先据 ① 求出 所对应的位数长度,以及在该长度下对应的数字大小。然后转五进制就可以了。
#include <bits/stdc++.h> using namespace std; using ll = long long; const ll mod = 1e9 + 7; ll n, m, C[101][101], f[15], b[] = {1, 2, 3, 5, 9}; void get(ll x) { for(int i = 1; ; i++) if(x <= f[i]) { vector<int> tmp; x--; for(int j = 0; j < i; j++) { tmp.push_back(x % 5); x /= 5; } for(int i = tmp.size() - 1; i >= 0; i--) cout << b[tmp[i]]; cout << endl; break; } else x -= f[i]; } int main() { for(int i = 0; i <= 100; i++) { C[i][0] = 1; for(int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod; } f[0] = 1; for(int i = 1; i < 15; i++) f[i] = f[i - 1] * 5; int T; cin >> T; while(T--) { cin >> n >> m; ll v = C[n][m]; get(v); } return 0; }
C 不平衡数组
设 表示 a[i] 是否 ,并且使 均不相同的最小代价。
然后分情况写一下 方程就好了。
如 ,那么若 ,则 不能 ,若若 不,则 必 。
即:
其它情况讨论一下就行。
具体 方程见代码。
#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 2e5 + 5; int n, a[N], b[N]; ll dp[N][2]; int main() { cin >> n; for(int i = 1; i <= n; i++) cin >> a[i] >> b[i]; a[0] = a[n + 1] = -10; for(int i = 1; i <= n; i++) { if(a[i] == a[i - 1]) { dp[i][1] = dp[i - 1][0] + b[i]; dp[i][0] = dp[i - 1][1]; } else if(a[i - 1] + 1 == a[i]) { dp[i][0] = dp[i - 1][0]; dp[i][1] = min(dp[i - 1][1], dp[i - 1][0]) + b[i]; } else if(a[i] + 1 == a[i - 1]) { dp[i][0] = min(dp[i - 1][0], dp[i - 1][1]); dp[i][1] = dp[i - 1][1] + b[i]; } else { dp[i][0] = min(dp[i - 1][0], dp[i - 1][1]); dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + b[i]; } } cout << min(dp[n][0], dp[n][1]) << endl; return 0; }
D 数列统计
算是一个结论题吧,做过几个基于这个结论出的题了。
当时的姿势应该是这个样子的:
先设 dp[i][j] 表示以 结尾,长度为 的不下降序列个数。那么 。其实就是 次前缀和。
4
然后呢打表找规律:
1 1 1 1 1 1 ... 1 2 3 4 5 ... 1 3 6 10 ... 1 4 10 ... 1 5 ... 1 ...
发现是一个斜着的杨辉三角。然后就可以得到答案就是 。
觉着不靠谱的话可以再证明一下。
然后预处理出阶乘 ,和阶乘逆元 ,即可 回答询问。
#include <bits/stdc++.h> using namespace std; const int N = 2e6 + 5; const int mod = 911451407; int f[N], g[N]; void init() { int n = 2e6; f[0] = 1; for(int i = 1; i <= n; i++) f[i] = 1l * f[i - 1] * i % mod; g[0] = g[1] = 1; for(int i = 2; i <= n; i++) g[i] = 1ll * (mod - mod / i) * g[mod % i] % mod; for(int i = 2; i <= n; i++) g[i] = 1ll * g[i - 1] * g[i] % mod; } int C(int n, int m) { return 1ll * f[n] * g[m] % mod * g[n - m] % mod; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); init(); int T; cin >> T; while(T--) { int n, m; cin >> n >> m; cout << C(n + m - 2, n - 1) << endl; } return 0; }