Codeforces Round891(Div3)
说在前面的话:
心血来潮想要补一场Div3,这些题目确实很有意思。英文题面真的难懂,但是洛谷上的简洁题面无疑降低了难度。
然后通过这次补题经历,更加感到了不开long long见祖宗,所以,读者可以发现有几道题用了signed
(源代码已经改成这样力,不想被long long再搞一次了)。
最后,碍于DevC++的功能有限,不能像VS Code等软件那样直接在界面进行类似文件读入输出的操作,使得界面十分清晰,所以还用什么DevC++个人认为文件读入输出操作更能辨别正确与否。
A
就是给出一个数组,将数组元素染上两种不同的颜色,判断是否存在某种染色方案,使得每种颜色的数字之和的奇偶性相同。
当然有结论:数字之和为偶数即可。不证。
我当时觉得把奇数偶数配对,这样一层一层算下去直到一方为\(0\)。属于瞎做做法(。
#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=100, INF=0x3f3f3f3f;
int T,n,a[N];
int ou,ji;
void f(int x,int y){
while(x!=0&&y!=0){
int k=min(x,y);
y-=k;
}
if(x==0)puts("YES");
else{
if(x%2==0)puts("YES");
else puts("NO");
}
}
int main(){
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
cin>>T;
while(T--){
cin>>n;
ou=0;ji=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]%2==0)ou++;
else ji++;
}
f(ji,ou);
}
return 0;
}
B
B就是将一个数字进行若干次(或不进行)五入的进位操作,求可得到的最大值。
很明显贪心,我们从右往左遍历,能进位就进位,记得处理一下\(9\)进位即可。
#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=800, INF=0x3f3f3f3f;
string s;
int T;
int main(){
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
cin>>T;
while(T--){
cin>>s;s='0'+s;
int num=s.size();
for(int i=s.size()-1;i>0;i--){
if(s[i]=='9'+1){
s[i]='0';
s[i-1]++;
}
if(s[i]>='5'){
num=i;
s[i-1]++;
}
}
for(int i=0;i<s.size();i++){
if(i==0&&s[i]=='0')continue;
if(i<num)cout<<s[i];
else cout<<0;
}
cout<<endl;
}
return 0;
}
C
构造题,题面很清楚了已经。
因为对于一个非下降数列\(a_1,a_2,...,a_n\),\(a_1\)要和\(n-1\)个数比较,所以也会有\(n-1\)个\(a_1\)出现在B中,后面以此类推。
#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=1e6+5, INF=0x3f3f3f3f;
int T,n,a[N],b[N];
int main(){
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
cin>>T;
while(T--){
cin>>n;
ll bn=n*(n-1)/2;
for(int i=1;i<=bn;i++)cin>>b[i];
sort(b+1,b+bn+1);
int i=1,j=n-1;
while(i<=bn){
cout<<b[i]<<' ';
i+=j;
j--;
}
cout<<b[bn]<<endl;
}
return 0;
}
D
题面更是清晰,洛谷上一概括确实好受不少(
一眼图论题,再一眼傻瓜题,如果按题目来做就是\(O(n^2)\),肯定超时,那我们就略微移项:
所以只需要求出最大差值,然后看看有几个和最大值一样的值就行了。
#include <bits/stdc++.h>
#define ll long long
#define re register
using namespace std;
const int N=2e5+5, INF=0x3f3f3f3f;
int T,n,a[N],b[N],maxn;
int main(){
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
cin>>T;
while(T--){
cin>>n;
maxn=-2e9;//这里注意,每个元素是[-1e9,1e9],这个最小有-2e9(错了好几次
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
cin>>b[i];
maxn=max(maxn,a[i]-b[i]);
}
int t=0;
vector<int> S;
for(int i=1;i<=n;i++)if(a[i]-b[i]==maxn){t++;S.push_back(i);}
cout<<t<<endl;
for(auto i:S)cout<<i<<' ';
cout<<endl;
}
return 0;
}
E
题目就是有\(n\)个点,放在数轴上面,对于其中一个数,计算它与其余各点(包括自身)之间点的个数之和。
一眼DP,但是后面没写成DP。这题只要愿意算,基本没啥问题(推的式子都没我以前写的几道复杂,而且也不用证明),单纯模拟即可:
我们记\(s_k\)表示第\(k\)个数的按题目所求的值。
前面三项我们可以直接算,后面两个可以用后缀和以及前缀和做。
(可以看出,这题被long long
背刺了)
#include <bits/stdc++.h>
#define ll long long
#define int long long
#define re register
using namespace std;
const int N=2e5+5, INF=0x3f3f3f3f;
int T,n,a[N],b[N];
ll pre[N],suf[N];
map<int,ll>ans;
signed main(){
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
cin>>T;
while(T--){
cin>>n;
memset(pre,0,sizeof(pre));
memset(suf,0,sizeof(suf));//多测记得清空
for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i];
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)pre[i]=pre[i-1]+a[i];//前缀和
for(int i=n-1;i>=1;i--)suf[i]=suf[i+1]+a[i+1];//后缀和
for(int i=1;i<=n;i++)ans[a[i]]=(2*i-n)*a[i]+n+suf[i]-pre[i];//套公式
for(int i=1;i<=n;i++)cout<<ans[b[i]]<<' ';
cout<<endl;
}
return 0;
}
F
题面
一眼梦回2022CSP-J,我们只需运用初中数学一元二次方程即可。
对于题中两个式子移项合并可得:
\(a_i\)可以换成\(a_j\),二者为方程\(x^2-bx+c=0\)的二根。
注意一下\(\Delta\)非负且能开尽,上面是偶数就行了。如果两根相同,那么\(ans=C_k^2=\dfrac{k(k-1)}{2}\),\(k\)就是值为\(a_i\)的数的个数,组合公式算得。如果两根不同,根据乘法定理,\(ans=k_1 * k_2\)。
(再次被long long
薄纱)
#include <bits/stdc++.h>
#define int long long
#define re register
using namespace std;
const int N=2e5+5, INF=0x3f3f3f3f;
map<int,int>check;
bool pd(int n){
int k=sqrt(n);
return k*k==n;
}
int delta(int x,int y){
int k=x*x-4*y;
if(k<0||!pd(k))return -1;
return sqrt(k);
}
int T,n,a[N],q;
signed main(){
/*freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);*/
cin>>T;
while(T--){
cin>>n;
check.clear();
for(int i=1;i<=n;i++){cin>>a[i];check[a[i]]++;}
cin>>q;
while(q--){
int ans=0;
int x,y;cin>>x>>y;
int del=delta(x,y);
if(del==-1||(x+del)%2!=0){
cout<<0<<' ';continue;
}
int N_x1=check[(x+del)/2],N_x2=check[(x-del)/2];
if((x+del)/2==(x-del)/2)ans=N_x1*(N_x1-1)/2;
else ans=N_x1*N_x2;
cout<<ans<<' ';
}
cout<<endl;
}
return 0;
}
G
emm不会,这个真是图论了。以后会了再补。