比赛链接:Dashboard - Codeforces Round 942 (Div. 2) - Codeforces
A题
翻译中文题面:
一场比赛包含 n 个问题,第 i 个问题的难度预期最多为 bi。已经有 n 个问题的提议,第 i 个问题的难度是 ai。最初,数组 a1,a2,…,an 和 b1,b2,…,bn 按非递减顺序排序。
一些问题可能比预期更难,所以写手必须提出更多问题。当提出难度为 w 的新问题时,最难的问题将被删除,问题将按非递减的难度排序。
换句话说,在每个操作中,你选择一个整数 w,将其插入数组 a,按非递减顺序排序数组 a,并从中删除最后一个元素。
找到使 ai≤bi 对所有 i 成立的新问题的最小数量。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t(1≤t≤100)。以下是测试用例的描述。
每个测试用例的第一行仅包含一个正整数 n(1≤n≤100),表示问题的数量。
每个测试用例的第二行包含长度为 n 的数组 a(1≤a1≤a2≤⋯≤an≤109)。
每个测试用例的第三行包含长度为 n 的数组 b(1≤b1≤b2≤⋯≤bn≤109)。
输出
对于每个测试用例,在新行中打印一个整数作为你的答案。
解题思路:
在a数组中寻找到第一个不满足的数,把它替换成数组b中的数即可。
AC代码:
#include<iostream>
using namespace std;
const int N=105;
int n,t;
int a[N],b[N];
int cheak(int a[],int b[]){//判断a数组任意一个数是否小于b数组对应位置的数for(int i=0;i<n;i++){if(a[i]>b[i]){return i;}}return -1;
}
int main(){cin>>t;while(t--){cin>>n;int sum=0;for(int i=0;i<n;i++){cin>>a[i];}for(int i=0;i<n;i++){cin>>b[i];}while(cheak(a,b)!=-1){int dep=cheak(a,b);//记录下标for(int i=n-1;i>=dep;i--){//数组右移a[i+1]=a[i];}a[dep]=b[dep];//替换sum++;}cout<<sum<<endl;}return 0;
}
B题:
翻译中文题面:
在桌子上有 n 枚硬币组成一个圆圈,每枚硬币都可能正面朝上或者背面朝上。Alice 和 Bob 轮流玩以下游戏,Alice 先开始。
在每一步操作中,玩家选择一枚正面朝上的硬币,移除该硬币,并翻转其相邻的两枚硬币。如果(在操作之前)只剩下两枚硬币,则一枚会被移除,另一枚不会被翻转(因为它将被翻转两次)。如果(在操作之前)只剩下一枚硬币,则不会翻转任何硬币。如果(在操作之前)没有正面朝上的硬币,则玩家输掉游戏。
决定在他们都以最优方式玩游戏时谁将赢得游戏。可以证明游戏将在有限步数内结束,其中一个玩家将获胜。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t(1≤t≤100)。以下是测试用例的描述。
每个测试用例的第一行仅包含一个正整数 n(1≤n≤100),表示硬币的数量。
每个测试用例的第二行包含一个长度为 n 的字符串 s,其中只包含 "U" 和 "D",表示每枚硬币是正面朝上还是背面朝上。
输出
对于每个测试用例,如果 Alice 将赢得游戏,则打印 "YES",否则打印 "NO"。
你可以以任何大小写形式输出答案。例如,字符串 "yEs"、"yes"、"Yes" 和 "YES" 都将被识别为肯定响应。
解题思路:
hhh,当你看完样例你就知道这是奇偶问题,当U的数量为奇数,Alice 将赢得游戏,偶数Bob赢得游戏。
AC代码:
#include<iostream>
#include<cstring>
using namespace std;
string s;
int t,n;
int main(){cin>>t;while(t--){cin>>n;int sumu=0;cin>>s;for(int i=0;i<s.size();i++){if(s[i]=='U')sumu++;}cout<<(sumu%2==0?"NO":"YES")<<endl;}return 0;
}
C题:
翻译中文题面:
你有一些卡片。每张卡片上都写着一个介于 1 和 n 之间的整数:具体来说,从 1 到 n 的每张 i ,你们有 ai 张写着数字 i 的卡片。
还有一个商店,里面有无限量的各种类型的卡片。您有 k 枚金币,因此您总共可以购买 k 张新卡片,您购买的卡片可以包含 1 到 n 之间的任意整数。
买完新牌后,你要将所有牌重新排列成一行。重新排列的得分是长度为 n 的(连续)子数组的数量,这些子数组是 [1, 2, ..., n] 的排列组合。你能得到的最高分是多少?
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t (1<=t<=100) 。测试用例说明如下。
每个测试用例的第一行包含两个整数 n , k ( 1<= n <=2 *10^5 , 0<=k<=10^12 )不同类型纸牌的数量和硬币的数量。
每个测试用例的第二行包含 n 个整数 a1, a2, ..., an ( 1<=ai <=10^12 ) 开始时拥有的 i 类型的纸牌数量。
保证所有测试用例中 n 的总和不超过 5 *10^5 。
输出
对于每个测试用例,输出一行包含一个整数的数据:你能得到的最大分数。
解题思路:
这个问题看上去是一个数的排列问题,无非就是求一个组合排列,里面有多少个[1--n]的组合数,看完给的测试数据之后,从第三组测试样例来看,3 4 6 1 8,我们可以看出来主要贡献最大分数的还是数字2(1个),这就说明了这个一组合要得到最大的分数,那就要看短板,这就相当于木桶效应,能乘多少水取决于木桶里面最短的一个木板。这个样例中数字1(6个)数字2(1个)数字3(8个),最少的是数字2,无论咋样组合,数字2只有一个,最多只能有两种组合(数字2左边组合,右边组合),那么我们有k枚金币,可以去买不同的数,那就要买这堆数里面最少的那个数,比如1 6 8,先把数字1买到跟数字2一样6个,再往后让数字1跟数字2买到跟数字3相同8个,再多了就三个一组一起买,所求的分数如何算。(a[i]+k/i)*n+n-i+k%i-n+1为了方便写在纸上,如下图:
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int t,n;
long long k,a[N];
int main(){scanf("%d",&t);while(t--){scanf("%d %lld",&n,&k);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}sort(a+1,a+n+1);//排序方便金币购买for(int i=1;i<=n;i++){if(i<n&&k>=(a[i+1]-a[i])*i){//金币足够买到与下一个数相同的个数k-=(a[i+1]-a[i])*i;}else{printf("%lld\n",max(0ll,(a[i]+k/i)*n+n-i+k%i-n+1));//由于涉及到减法,防止答案为负数,与0取最大值break;}}}return 0;
}
D1题:
翻译中文题面:
两个版本的问题不同。您可能需要同时阅读两个版本。只有两个版本的问题都解决了,您才能进行破解。
给你两个正整数 n , m 。
计算满足以下条件的有序数对 (a, b) 的个数:
- 1<=a<=n , 1<=b<=m ;
- a+b 是 b *gcd(a,b) 的倍数。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t ( 1<=t<=10^4 )。测试用例说明如下。
每个测试用例的第一行包含两个整数 n , m (1<=n,m<=2 *10^6 )。
保证所有测试用例中 n 和 m 的总和不超过 2 *10^6 。
输出
为每个测试用例打印一个整数:有效配对的数量。
注
在第一个测试案例中,只有 (1,1) 满足条件。
在第四个测试用例中, (1,1),(2,1),(2,2),(3,1),(4,1),(5,1),(6,1),(6,2),(6,3),(7,1),(8,1),(9,1),(10,1),(10,2) 满足条件。
解题思路:
AC代码:
#include<iostream>
using namespace std;
typedef long long ll;
int n,m,t;
ll ans;
int main(){cin>>t;while(t--){cin>>n>>m;ans=0;for(int i=1;i<=m;i++){ans+=(n+i)/(1ll*i*i);}cout<<ans-1<<endl;}return 0;
}
D2题:
翻译中文题面:
两个版本的问题不同。您可能需要同时阅读两个版本。只有两个版本的问题都解决了,您才能进行破解。
给你两个正整数 n , m 。
计算满足以下条件的有序数对 (a, b) 的个数:
- 1<=a<=n, 1<=b<=m ;
- b*gcd(a,b) 是 a+b的倍数。
解题思路:
与上一个D1题倒过来了,假设都与上一个题一样的思路。这里粘一个官方题解。
AC代码:
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int t,n,m;
int main(){cin>>t;while(t--){cin>>n>>m;int ans=0;for(int i=1;i<=sqrt(n);i++){for(int j=1;j<=sqrt(m);j++){if(__gcd(i,j)==1){ans += min(n/(i*(i+j)),m/(j*(i+j)));}}}cout<<ans<<"\n";}return 0;
}