只过了ADFGJ
其他待补
A 贪心
考虑一下,如果数字一样,这人还是会排在前面的所有人里的最后一名,那么m肯定先给自己加一个,然后因为≥他的人不管加不加都在他前面,所以给数字≥他的都加上,如果m还有剩余,考虑从最小的加,尽量减少他后面的人谁提高到和他一样(因为他字典序最大)
所以排序一下,对他前面的人进行加,还有剩余,就从最小的开始加。再次排序找他的名次即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; struct node { ll x; ll id; } a[200005]; int main() { int t; cin >> t; while (t--) { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i].x; a[i].id = i; } a[1].x++; ll e = a[1].x; m--; sort(a + 1, a + 1 + n, [](node a, node b) { if (a.x != b.x) return a.x < b.x; return a.id < b.id; }); int k = 0; for (int i = 1; i <= n && m; i++) { if (a[i].id == 1) { k = i; continue; } if (a[i].x >= e) a[i].x++, m--; } for (int i = 1; m && i < k; i++) { a[i].x++, m--; } sort(a + 1, a + 1 + n, [](node a, node b) { if (a.x != b.x) return a.x < b.x; return a.id < b.id; }); int flag = 0; for (int i = n; i; i--) { if (a[i].id == 1) { flag = n - i + 1; break; } } cout << flag << endl; } return 0; }
D 简单数学
n个人可以看成一个集合,那么一个集合中,有 个子集,因为每个子集要么有这个人,要么没这个人。
那么刨除这个当队长的人,还有n-1个人,也就是还有 个集合,有m个人能当队长,答案自然就是
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; ll qpow(ll a,ll b){ ll ans=1; while(b){ if(b&1) ans=a*ans%mod; a=a*a%mod; b/=2; } return ans; } int main(){ int t;cin>>t; while(t--){ ll n,m;cin>>n>>m; cout<<m*qpow(2,n-1)%mod<<endl; } return 0; }
F 简单找规律
可以发现第n个字符串中,第一个串出现的次数是 次 第二个串出现的次数是 次
其中f是斐波那契数列。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; ll f[45]; int main() { ll s[130] = {0}, d[130] = {0}; string a, b; cin >> a >> b; int n; cin >> n; f[1] = f[2] = 1; for (int i = 3; i <= n; i++) { f[i] = f[i - 1] + f[i - 2]; } ll q, w; if (n >= 3) q = f[n - 2], w = f[n - 1]; else if (n == 1) q = 1, w = 0; else q = 0, w = 1; for (int i = 0; a[i]; i++) s[a[i]]++; for (int i = 0; b[i]; i++) d[b[i]]++; for (int i = 'A'; i <= 'Z'; i++) { if (s[i]&&q || d[i]&&w) cout << (char)i << ": " << s[i]*q + d[i]*w << endl; } for (int i = 'a'; i <= 'z'; i++) { if (s[i]&&q || d[i]&&w) cout << (char)i << ": " << s[i]*q + d[i]*w << endl; } return 0; }
G 博弈思想
考虑一下,最后的答案其实是取决于第三个人,因为他是最后一个剔除最后一个数的人。
那么他想要的肯定是要离0近的,那么第二个人就要去考虑第三个人怎么想的,第三个人肯定取离0近的,所以固定第一个人,固定第二个人后得到的和后取最小,这是第三个人想要的,那么回到第二个人,固定第一个人,枚举第二个人,他想要最小的,所以就是所有的离0近的里在取最小的。
那么对于第一个人要最大的,他就要考虑第二个人第三个人的情况,所以答案就是离0近的里最小的里的最大的。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; int a[105], b[105], c[105]; ll q[105]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int j = 1; j <= n; j++) cin >> b[j]; for (int k = 1; k <= n; k++) cin >> c[k]; ll ma=-1e9; for (int o = 1; o <= n; o++) { ll ans = 1e9,x=a[o]; for (int i = 1; i <= n; i++) { int cnt = 0; for (int j = 1; j <= n; j++) { q[++cnt] = b[i] + c[j] + x; } sort(q + 1, q + 1 + cnt); int k = lower_bound(q + 1, q + 1 + cnt, 0) - q; ll sum; if (k == cnt + 1) sum = q[k - 1]; else { if (k == 1) sum = q[k]; else { if (q[k] > -q[k - 1]) sum = q[k - 1]; else sum = q[k]; } } ans = min(ans, sum); } ma=max(ma,ans); } cout << ma << endl; return 0; }
J 组合数学 卡特兰数+可重集排列数
容易发现,一个右上走+一个右下走就等于一个往右走两步。
考虑一下第一个点,不能走到y下面,对y坐标影响的只有右上和右下,那么我们把右上看成一个左括号,右下看成一个右括号,求合法括号方案数,那么其实方案数就是一个卡特兰数。
那么这样的话,对于右上右下的已经处理好了,还差一个直接往右走的有i个,那么考虑这两部分结合,容易发现是一个可重集排列数,那么对于每个合法括号数里结合i个直接往右走的方案数有
其中分子就是总的组成个数,右上右下总共有2(n-i)个,直接右走有i个,所以一共是2n-i个。
那么最后答案就是
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 998244353; ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans = a * ans % mod; a = a * a % mod; b /= 2; } return ans; } ll f[300005]; int main() { f[0]=1; for(int i=1;i<=300000;i++){ f[i]=f[i-1]*i%mod; } int n;cin>>n; ll ans=0; for(int i=0;i<=n;i++){ ll sum=1; ll cat=f[2*(n-i)]*qpow(f[(n-i)]*f[(n-i)]%mod*((n-i)+1)%mod,mod-2)%mod;//卡特兰数部分 sum=f[2*n-i]*qpow(f[i]*f[2*(n-i)]%mod,mod-2)%mod;//可重集部分 ll q=cat%mod*sum%mod; ans=(ans+q)%mod; } cout<<ans<<endl; return 0; }