[Codeforces Round #698 (Div. 2)] A-F题解
A.Nezzar and Colorful Balls
思路:
贪心,等价求众数的次数
#include<bits/stdc++.h>
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
typedef double db;
int t,n;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>t;
int ans=0,now,a;
while(t--){
ans=1;
cin>>n;
cin>>a;
now=a;
int mx=1;
for(int i=1;i<=n-1;++i){
cin>>a;
if(now==a)mx++;
else{
ans=max(ans,mx);
mx=1;
now=a;
}
}
ans=max(ans,mx);
cout<<ans<<"\n";
}
return 0;
}
B.Nezzar and Lucky Number
题意:判断给出的数字能否分解为若干个数字之和且这几个数字的数位上存在数字d
思路:个人认为这道题全场最难,其他题都没卡我,就这道题卡了我。若原数字 > = 10 d >=10d >=10d,则可以通过减去10d+1…10d+9,使得最后个位均为d,若 < 10 d <10d <10d,则分解之后只有个位是d,所以直接暴力枚举-10,-20xxxx是否能整除d即可
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <bitset>
#include <algorithm>
#define LL long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=2e5+5;
bool check(int x,int d) //判断x是否合法的函数
{
if(x>=10*d) return true; //nd(1<=n<=10)的个位数包含了0-9所有的个位数,因此大于等于10*d的x一定是合法的
for(int i=1;i*d<=x;i++) //枚举所有小于等于x的d的倍数
if(i*d%10==x%10) return true; //如果有符合条件的则返回true
return false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,d;
scanf("%d%d",&n,&d);
while(n--)
{
int x;
scanf("%d",&x);
if(check(x,d)) puts("YES");
else puts("NO");
}
}
return 0;
}
C.Nezzar and Symmetric Array
题意:根据 d i d_i di还原 a i a_i ai
思路:
由于对称,所以一个点x到其他对称点y,-y,要么是2x,要么是2y。所以必须满足以下条件
1.对称
2.%2==0
所以对于最大、次大的 d i d_i di
最大 d i = 2 ∗ m a x ( a i ) ∗ n d_i=2*max(a_i)*n di=2∗max(ai)∗n
次大 d i = 2 ∗ 次 大 a i ∗ ( n − 1 ) + 2 ∗ 最 大 a i d_i=2*次大a_i*(n-1)+2*最大a_i di=2∗次大ai∗(n−1)+2∗最大ai
所以可以O(N)检验推出即可
但是这道题很多坑,首先 a i a_i ai不能重复,其次这样设的话, a i > = 0 a_i>=0 ai>=0
#include<bits/stdc++.h>
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
typedef double db;
const int maxn=2e5+5;
int t,n;
ll d[maxn];//两倍数组
map<ll,int>cnt,cnt2;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>t;
while(t--){
cnt.clear();
cnt2.clear();
cin>>n;
for(int i=1;i<=2*n;++i)cin>>d[i],cnt[d[i]]++;
sort(d+1,d+1+2*n);
bool f=1;
for(int i=1;i<=2*n;++i){
if(cnt[d[i]]%2!=0||d[i]%2!=0)f=0;
}
if(!f){
cout<<"NO"<<"\n";
continue;
}
ll D=d[2*n];
if(D%(2*n)!=0)f=0;
ll now=D/(2*n);
cnt2[now]++;
ll sum=now;
for(int i=n-1;i>=1;--i){
if(!f)break;
ll D=d[2*i];
if((D-2*sum)%(2*i)!=0)f=0;
now=(D-2*sum)/(2*i);
sum+=now;
if(cnt2[now]==1)f=0;
cnt2[now]++;
if(now<=0)f=0;
}
cout<<(f?"YES":"NO")<<"\n";
}
return 0;
}
D.Nezzar and Board
思路:
煞笔题,容易发现就是x+k1x1…=k是否有解, x i x_i xi就是两两 a i a_i ai的差,显然顺序两两做差可以线性组合出所有的 x i x_i xi,所以 根据裴蜀定理秒了
#include<bits/stdc++.h>
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define ls p<<1
#define rs p<<1|1
using namespace std;
typedef long long ll;
typedef double db;
const int maxn=2e5+5;
int t,n;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
ll a[maxn],k;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>t;
while(t--){
cin>>n>>k;
for(int i=1;i<=n;++i)cin>>a[i];
ll G=a[2]-a[1];
for(int i=3;i<=n;++i)
G=gcd(G,a[i]-a[i-1]);
bool flag=0;
for(int i=1;i<=n;++i){
if((k-a[i])%G==0){
flag=1;break;
}
}
cout<<(flag?"YES":"NO")<<"\n";
}
return 0;
}
E.Nezzar and Binary String
题意:
给定初始序列与结果序列,并给出q个查询区间,每次查询后可以将相应的区间内小于一半数量的数进行更改,问是否存在相应的操作满足每次查询到的区间只包含0或1并且最终更改后的初始序列与结果序列相同。
思路:
正着考虑很难做,不知道如何修改,正难则反,反着就变成先考虑是否能够清空,然后再改回满的,最后如果和原序列相同即可,所以对最终序列建立一颗维护区间赋值、区间查询的线段树即可
#include<bits/stdc++.h>
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define ls p<<1
#define rs p<<1|1
using namespace std;
const int maxn=2e5+5;
typedef long long ll;
typedef double db;
int t,n,q;
char s1[maxn],s2[maxn];
struct SegmentTree{
int num[maxn<<2],add[maxn<<2];
void pushUp(int p){
num[p]=num[ls]+num[rs];
}
void build(int p,int l,int r){
add[p]=-1;
if(l==r){
num[p]=(s2[l]=='1');
return;
}
int mid=l+r>>1;
build(lson);
build(rson);
pushUp(p);
}
int query(int p,int l,int r,int L,int R){
if(L<=l&&r<=R)return num[p];
pushDown(p,l,r);
int mid=l+r>>1,ans=0;
if(L<=mid)ans+=query(lson,L,R);
if(R>mid)ans+=query(rson,L,R);
return ans;
}
void pushDown(int p,int l,int r){
if(add[p]==-1)return;
int mid=l+r>>1;
num[ls]=(mid-l+1)*add[p];
num[rs]=(r-mid)*add[p];
add[ls]=add[rs]=add[p];
add[p]=-1;
}
void update(int p,int l,int r,int L,int R,int val){
if(L<=l&&r<=R){
num[p]=(r-l+1)*val;
add[p]=val;
return;
}
int mid=l+r>>1;
pushDown(p,l,r);
if(L<=mid)update(lson,L,R,val);
if(R>mid)update(rson,L,R,val);
pushUp(p);
}
}tr;
int L[maxn],R[maxn],sum[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>t;
while(t--){
cin>>n>>q;
cin>>(s1+1)>>(s2+1);
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+(s1[i]=='1');
for(int i=1;i<=q;++i)cin>>L[i]>>R[i];
tr.build(1,1,n);
bool is=1;
for(int i=q;i>=1;--i){
int cnt1=tr.query(1,1,n,L[i],R[i]),cnt2=R[i]-L[i]+1-cnt1;
if(cnt1==cnt2){
is=0;break;
}
tr.update(1,1,n,L[i],R[i],cnt1>cnt2);
}
if(!is){ cout<<"NO"<<"\n";continue;}
for(int i=1;i<=n;++i){
if(sum[i]!=tr.query(1,1,n,1,i)){
is=0;break;
}
}
cout<<(is?"YES":"NO")<<"\n";
}
return 0;
}
F.Nezzar and Nice Beatmap
题意:为求出n个点的排列顺序,使得其中任意连续3个点所形成的角都为锐角。
思路:
首先一定存在,如何构造,每次选最远距离的点,由勾股定理必定可解,但是其实还有更方便的写法,就是直接类似冒泡排序,暴力叉积暴力判断,因为最后一定有解,所以一定可以确定下来
另外这题卡精度,不要用double,用ll判断,不然就wa 120
#include<bits/stdc++.h>
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef double db;
int t,n;
ll dis(ll X1,ll Y1,ll X2,ll Y2){
return (X1-X2)*(X1-X2)+(Y1-Y2)*(Y1-Y2);
}
pair<int,int>P[5050];
int ans[5050],cnt=0;
bool vis[5050];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;++i)cin>>P[i].fi>>P[i].se;
ans[++cnt]=1;
vis[1]=1;
int now=1,nex=1;
while(cnt<n){
ll mx=0;
for(int j=1;j<=n;++j){
if(vis[j])continue;
if(dis(P[now].fi,P[now].se,P[j].fi,P[j].se)>mx){
mx=dis(P[now].fi,P[now].se,P[j].fi,P[j].se);
nex=j;
}
}
ans[++cnt]=nex;
vis[nex]=1;
now=nex;
}
for(int i=1;i<=cnt;++i)cout<<ans[i]<<" ";
return 0;
}