题解
【基础】游戏
9 条题解
-
0
#include<bits/stdc++.h> using namespace std; long long a[201000], n; // a: 存储所有卡牌数值, n: 卡牌数量 long long xia[201000], men[201000]; // xia: 小厦获得的牌, men: 阿门获得的牌 long long l, r; // l: 小厦牌数计数器, r: 阿门牌数计数器 long long sum1 = 0, sum2 = 0; // sum1: 小厦初始总分, sum2: 阿门初始总分 int main() { // 输入卡牌数量 cin >> n; // 输入所有卡牌数值 for(int i = 1; i <= n; i++) cin >> a[i]; // 将卡牌按数值从大到小排序(降序排列) sort(a + 1, a + 1 + n, greater<int>()); // 模拟轮流取牌过程:小厦先手,取奇数位置的牌;阿门后手,取偶数位置的牌 for(int i = 1; i <= n; i++) { if(i % 2 == 1) { // 小厦取牌:当前轮次为奇数,小厦取走当前最大的牌 xia[++l] = a[i]; // 将牌加入小厦的手牌 sum1 += a[i]; // 累加到小厦的总分 } else { // 阿门取牌:当前轮次为偶数,阿门取走剩余牌中最大的牌 men[++r] = a[i]; // 将牌加入阿门的手牌 sum2 += a[i]; // 累加到阿门的总分 } } /* * 核心博弈分析:阿门有一次交换机会 * 最优交换策略:阿门会用自己最小的牌(men[r])换小厦最大的牌(xia[1]) * 交换后变化: * 小厦新总分 = sum1 - xia[1] + men[r] (失去最大牌,获得阿门最小牌) * 阿门新总分 = sum2 - men[r] + xia[1] (失去最小牌,获得小厦最大牌) * * 总分差分析: * 交换前总分差 = sum1 - sum2 * 单次交换影响 = xia[1] - men[r] (这是交换对总分差的改变量) */ if(sum1 - sum2 == xia[1] - men[r]) { // 情况1:交换对总分差无影响,交换没有意义 // 保持初始分配结果,双方平局 cout << sum1 << " " << sum2 << endl; cout << "p"; // 输出平局 } else if(sum1 - sum2 < xia[1] - men[r]) { // 情况2:交换会扩大阿门的优势或缩小小厦的优势 // 阿门选择交换后能够获得更大优势 cout << sum1 - xia[1] + men[r] << " " << sum2 + xia[1] - men[r] << endl; cout << "m"; // 阿门获胜 } else { // 情况3:即使交换后,小厦仍然保持优势 // 阿门仍然会选择交换来最大化自己的收益 cout << sum1 - xia[1] + men[r] << " " << sum2 + xia[1] - men[r] << endl; cout << "x"; // 小厦获胜 } return 0; } -
0
#include<bits/stdc++.h> using namespace std; int a[105][105]; int main() { int n, maxi = 1, mini = 1; cin >> n; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cin >> a[i][j]; } } for (int i = 1; i <= n; i++) { //查找第i行最小值对应的列下标 mini = 1; for (int j = 1; j <= n; j++) { if (a[i][j] < a[i][mini]) mini = j; } //查找第i列最大值对应的行下标 maxi = 1; for (int j = 1; j <= n; j++) { if (a[j][i] > a[maxi][i]) maxi = j; } swap(a[i][mini], a[maxi][i]); sort(a[i] + 1, a[i] + n + 1); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cout << a[i][j] << ' '; } cout << endl; } return 0; } -
0
#include<bits/stdc++.h> using namespace std; int main() { long long y, t; cin >> y >> t; // 判断正负 if(y >= 0){ cout << "NO"<<endl; } else { if(t % 2==1){ cout << "YES"<<endl; } else{ cout << "NO"<<endl; } } // 判断奇偶 if(y % 2 == 0) { if(t == 0){ cout << "YES"<<endl; } else{ cout << "NO"<<endl; } } else{ cout << "YES"<<endl; } return 0; } -
0
#include<bits/stdc++.h> using namespace std; /* 首先,根据题意,给出的数据最小值必须是1,否则一定是No。 考虑以贪心的思路来放弹珠,从第二堆开始,都优先凑出数量少的,因为如果先凑数量多的显然更大概率出现凑不出的情况。 由于可以将新的一堆弹珠摆放在任意位置,所以小朋友摆出来的弹珠序列的顺序实际上与题解无关,我们可以将每一堆弹珠的数量从小到大进行排序。 接着就是考虑从小到大每堆弹珠能否通过挑选若干堆已有弹珠拼凑而成,实际上只要保证下一堆弹珠的数量不超过已有弹珠数量的总和,就一定能够凑足(可以证明) 因此只要先从小到大排序,遍历每一堆的弹珠,判断当前堆弹珠数量是否不超过前面所有弹珠数量的和。 */ int t, n; // t代表组数 n代表每组的数字个数 int s[1123]; int main() { cin >> t; while (t--) { cin >> n; for (int i = 1; i <= n; i++) { cin >> s[i]; } // 因为每组的数字是可以随意放的,所以sort排序不影响结果的 // sort后可以帮助我们查看每个数字是如何得来的 sort(s + 1, s + n + 1); // 第一个不是1的话不满足题意 if (s[1] != 1) { cout << "No" << endl; continue; } // 将第一个数字给sum,也就是1 long long sum = s[1]; int flag = 1; // 检查这组数中数字能不能互相搭配出来,用标记写法去判断 for (int i = 2; i <= n; i++) { // 这道题核心的思维:任何一组数据,从小到大排序后,只要后面的数字(an)小于等于前面所有数字的总和(a1,a2...) // 那这个an一定能够拼凑出来,随便举例子都可以 if (s[i] <= sum) { sum += s[i]; } else { flag = 0; break; } } if (flag) { cout << "Yes" << endl; } else { cout << "No" << endl; } } return 0; } -
0
#include <bits/stdc++.h> using namespace std; /* 该题可以使用动态规划来解决: 举例 10 2 3 4 定义dp[i] 表示c到i的方案数 状态转移 dp[i] = dp[i - a] + dp[i - b] 但需要考虑 i - a 或 i - b 小于c时,对答案的贡献是1 */ const int MOD = 1e9 + 7; int dp[200005]; int main(){ int n, a, b, c; cin >> n >> a >> b >> c; dp[c] = 1; for (int i = c + 1; i <= n; i++) { if (i - a >= c) { dp[i] += dp[i - a]; } else { dp[i]++; } if (i - b >= c) { dp[i] += dp[i - b]; } else { dp[i]++; } dp[i] %= MOD; } cout << dp[n]; return 0; } -
0
#include <bits/stdc++.h> using namespace std; long long a[100005],p[100005];// 记录小怪血量的累加值 int main() { long long n,i,x,y,sum=0,ans=1e18; cin>>n>>x>>y; for(i=1; i<=n; i++) cin>>a[i]; sort(a+1, a+n+1);// 小怪血量升序 for (i=1; i<=n; i++) p[i] = p[i - 1] + a[i];// 前缀和记录小怪血量的累加值 if(x<=n){//使用1技能比较划算 for(i=0; i<=n; i++){//枚举秒杀次数(从血量最高的开始) sum = 0; // 本次杀死所有怪所需要的花费 int g = n-i; // 剩余的怪数量 sum += i * y;// 秒杀怪的花费 sum += a[g-x] * x;// 使用技能1,将怪杀到只剩下x只 /* 剩下的x只,在上面使用技能1的时候,每一只被扣血量为a[g-x], 所以剩下的x只,被扣的总血量=a[g-x] * x。 =>剩余的总血量(即最后需要用普攻的花费) =前缀区间血量和 - 被扣的总血量 */ sum += (p[g] - p[g-x]) - a[g-x] * x; ans = min(ans, sum);// 取每次的最小值 } cout << ans; }else{ //使用普攻或技能2秒杀,针对每个怪,取最小值消耗 for(i=1; i<=n; i++){ sum += min(a[i],y); } cout<< sum; } return 0; } -
0
#include <cstdio> #include <algorithm> using namespace std; int n, r; int A[100005]; int main(){ scanf("%d%d", &n, &r); int cnt = 0; for(int i=1; i<=n; i++){ int a; scanf("%d", &a); if(A[a] == 0) cnt++; A[a]++; } int t = 0; for(int i=0; i<=100005; i++){ if(A[i] > 0){ t++; if(1LL*(cnt-t)*r < i){ printf("%d", cnt-t+1); return 0; } } } return 0; }
- 1