Codeforces Round #698 (Div. 2)
A. Nezzar and Colorful Balls
Problem:
n 个数,相同的数需要图上不同的颜色,问最少一共需要多少种不同的颜色?
Solution:
计算相同数的个数,个数最多的就是答案。
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define _for(i,s,t) for(int i=s;i<t;i++) #define _rof(i,s,t) for(int i=s;i>t;i--) #define rep(i,s,t) for(int i=s;i<=t;i++) #define per(i,s,t) for(int i=s;i>=t;i--) #define Ri(x) scanf("%d",&x) #define Rii(x,y) scanf("%d%d",&x,&y) #define INF 0x3f3f3f3f using namespace std; template<class T>inline void read(T &res) { char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; } typedef long long ll; const int maxn = 1e2 + 10; int cnt[maxn]; int main(){ IOS; int t,n,v,ans; cin>>t; while(t--){ memset(cnt,0,sizeof(cnt)); cin>>n; ans = 0; rep(i,1,n){ cin>>v; cnt[v] ++; ans = max(ans,cnt[v]); } cout<<ans<<endl; } return 0; }
B. Nezzar and Lucky Number
Problem:
输入 q,d,q 表示 q 个询问,每个询问输入一个数字 ai ,问能否用 n 个十进制中包含 d 的数字求和得到 ai
eg:q = 2,d = 7。ai = 24 为YES(17 + 7 = 24),ai = 25 为NO
Solution:
思维题。
我们首先能够知道 1 ~ (d - 1) 的数字都为NO,并且 res = p + d * i (p = [ 1 ~ (d - 1)] )(对于每个 p 来说 i 从 1 自增,直到res的位数中出现了 7),res也为NO。我们将 d 从 1 到 9 的所有不符合的数字找出来即可。
eg:d = 7
1 8 15 22 29 36 43 50 57 2 9 16 23 30 37 3 10 17 4 11 18 25 32 39 46 53 60 67 5 12 19 26 33 40 47 6 13 20 27 7 以上除去每行的最后一位,即是 d = 7 时的所有为 NO 的数。(从上面可以知道,除去这些数,后面的所有数都是 YES。(ps:一列一列的观察))
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define _for(i,s,t) for(int i=s;i<t;i++) #define _rof(i,s,t) for(int i=s;i>t;i--) #define rep(i,s,t) for(int i=s;i<=t;i++) #define per(i,s,t) for(int i=s;i>=t;i--) #define Ri(x) scanf("%d",&x) #define Rii(x,y) scanf("%d%d",&x,&y) #define INF 0x3f3f3f3f using namespace std; template<class T>inline void read(T &res) { char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; } typedef long long ll; const int maxn = 1e5 + 10; vector<int> v[10]; bool isOk(int number,int pos){ while(number){ if(number % 10 == pos) return true; number /= 10; } return false; } void init(){ rep(i,1,9){ rep(s,1,i){ int num = s; while(true){ if(isOk(num,i)) break; v[i].push_back(num); num += i; } } } } bool check(int index,int val){ for(int i = 0;i < v[index].size();i ++){ if(v[index][i] == val) return false; } return true; } int main(){ IOS; init(); int t,q,d,val; cin>>t; while(t --){ cin>>q>>d; while(q--){ cin>>val; if(check(d,val)){ cout<<"YES"<<endl; }else{ cout<<"NO"<<endl; } } } return 0; }
C. Nezzar and Symmetric Array
Problem:
给的一个已知的数组 d,我们知道 d 数组中的每个数都是由 a 数组得来(a 数组是若数组中有 a[ i ] ,那么一定会存在 -a[ i ],并且不会出现重复的数)
(即 di 等于 ai 减去 a 数组中的每一个数字并取绝对值求和得来)
现在问是否能够找到 a 数组,使得能够求出给出得 d 数组,可以得话就输出yes。
Solution:
(最开始陷入到 d 数组不同数字得差值是否可以判断出YES,NO去了,搞了半天发现了在计算每个 di 时,数字之间的关系,不过比赛也就要结束了!!!)
在求解 di 的式子中,我们可以发现,其实对于 a[ i ] 来说,所有绝对值比它大的数字 a[ j ] (a[ j ] > a[ i ]) 的贡献都是 2 * a[ j ](因为 | a[ i ] - a[ j ] | + | a[ i ] - (- a[ j ]) | = 2 * a[ j ] ),所有绝对值比 a[ i ] 小的数字贡献都是 2 * a[ i ] (原因同上),它自己的贡献为 2 * a[ i ]。
因此
d1 = a1 * 2 + (a2 + .... + an)* 2
d2 = a2 * 2 + a2 * 2 * 1 + (a3 + .... an)*2
d3 = a3 * 2 + a3 * 2 * 2 + (a4 + .... an)*2
di = ai * 2 + ai * 2 * (i - 1) + (a(i + 1) + .... an)*2
.....
dn = an * 2 + an * 2 * (n - 1)
所以根据上面的式子我们可以根据 d 数组求出 a 数组,若求不出,或者求出的 a 数组中出现相同的数字,则表示 a 数组不存在,反之存在。
ps:倒着求,先求an 再求 a(n - 1) ........
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define _for(i,s,t) for(int i=s;i<t;i++) #define _rof(i,s,t) for(int i=s;i>t;i--) #define rep(i,s,t) for(int i=s;i<=t;i++) #define per(i,s,t) for(int i=s;i>=t;i--) #define Ri(x) scanf("%d",&x) #define Rii(x,y) scanf("%d%d",&x,&y) #define INF 0x3f3f3f3f using namespace std; template<class T>inline void read(T &res) { char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; } typedef long long ll; const int maxn = 2e5 + 10; vector<ll> v; ll a[maxn]; int main(){] IOS; int t,n; ll p; cin>>t; while(t --){ v.clear(); cin>>n; rep(i,1,2*n){ cin>>p; v.push_back(p); } sort(v.begin(),v.end()); bool ans = true; for(int i = 0;i < 2*n;i +=2){ if(v[i] != v[i + 1] || v[i] % 2 != 0){ ans = false; break; } } v.erase(unique(v.begin(),v.end()),v.end()); if(!ans || v.size() != n){ cout<<"NO"<<endl; continue; } ll sum = 0; int in = 0; for(int i = n - 1;i >= 0;i --){ if((v[i] - sum) % (2*(i + 1)) != 0){ ans = false; break; } a[i] = (v[i] - sum)/(2*(i + 1)); if(a[i] <= 0){ ans = false; break; } sum += a[i]*2; } if(ans){ cout<<"YES"<<endl; }else{ cout<<"NO"<<endl; } } return 0; }
D. Nezzar and Board
................................. 略 ...........................................
(裴蜀定理)
最终解为是否存在 (k - a[ i ]) % gcd(a[ 1 ],a[ 2 ],a[ 3 ],a[ 4 ],.......,a[ n ]) == 0,存在为YES
E. Nezzar and Binary String
Problem:
给定字符串 s1 和 s2 ,问有 q 个修改,经过 q 个修改后 s1 能否变成 s2。
对于每个修改,首先给定区间 [ l ,r ],若 s1 在区间中的所有字符都一样的话,则允许修改 ( r - l ) / 2 个字符(可以修改 <= ( r - l ) / 2个字符)。注意,若某个操作不能进行,则表示无法将 s1 变成 s2 ,因为若 [ l ,r ],若 s1 在区间中的所有字符不一样的话,改段字符会被丢弃。
Solution:
首先,我们对于 [ l,r ] 修改来说,我们需要判断 s1 在这个区间内的字符是否相等,若是相等的话,我们就进行字符的修改。可是问题是我们改如何修改呢?
........................................................................
竟然不能将 s1 变成 s2,那么我们考虑是否能将 s2 变成 s1,由于 s1 变成 s2 是先看 [ l,r ] 的 s1 是否相等,相等的话就就进行修改,所以 s2 变成 s1 则变成了至多修改 [ l,r ] 中的 不到一半 个字符后 s2 中 [ l,r ] 段的字符能否一致,最后进行了所有操作之后,看 s2 是否等于 s1 即可。(所有的操作都需要倒过来,所以修改操作也需要倒过来,即从最后一个区间遍历到第一个区间)
ps:由于 [ l,r ] 所有字符一致后,修改其至多 不到一半 个字符,我们无法确定改如何修改,而修改其至多 不到一半 个字符使得 [ l,r ] 一致,我们可以得出一定是将其中所有 0 变成 1 ,或者将其中所有的 1 变成 0,由于至多修改 不到一半 个字符,所以我们只能将其中min(num0,num1)进行修改。(num0 代表 0 的数量,num1 代表 1 的数量)。至于为什么要将 s2 的 [ l,r ] 区间的字符修改成一样的呢,因为我们需要将 s2 变成 s1 而对于 s1 来说,如果它能够进行所有的操作,意味着它每一个操作前 [ l,r ] 区间的字符都相等,所以我们只需要将其变成相等的。
由上面分析,我们可以知道其实如果给出的题目是允许我们转换成其它题意的情况下,我们可以试着进行相应的转换,然后进行思考。此题就是从结果往前推,也就是假设我们能够转换成 s1 ,而我们现如今每一步都是需要考虑当前必须是可以进行的,且是正确的,所以就变成了当前至多修改 不到一半 字字符后,[l,r] 区间的字符一定是相等的。
有了上面的理论之后,我们就需要考虑编码操作了,由于这是一个序列区间的修改和区间的查询,所以我们可以用线段树进行处理。对于修改操作,我们先查询区间[l,r] 的 0 和 1 的数量,若两者数量相等则表示无法进行操作,反之,将少的改成多的。最终在和 s1 进行比较即可。
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define _for(i,s,t) for(int i=s;i<t;i++) #define _rof(i,s,t) for(int i=s;i>t;i--) #define rep(i,s,t) for(int i=s;i<=t;i++) #define per(i,s,t) for(int i=s;i>=t;i--) #define Ri(x) scanf("%d",&x) #define Rii(x,y) scanf("%d%d",&x,&y) #define INF 0x3f3f3f3f using namespace std; template<class T>inline void read(T &res) { char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; } typedef long long ll; const int maxn = 2e5 + 10; char s1[maxn],s2[maxn]; int lazy[maxn << 2],tree[maxn << 2];// 存 '1' 的个数 struct Node{ int l,r; }nd[maxn]; void build(int k,int l,int r){ lazy[k] = -1; tree[k] = 0; if(l == r){ tree[k] = s2[l] - '0'; return ; } int mid = (l + r) >> 1; build(k << 1,l,mid); build(k << 1 | 1,mid + 1,r); tree[k] = tree[k << 1] + tree[k << 1 | 1]; } void push_down(int k,int l,int r){ lazy[k << 1] = lazy[k << 1 | 1] = lazy[k]; int mid = (l + r) >> 1; tree[k << 1] =lazy[k] * (mid - l + 1); tree[k << 1 | 1] = lazy[k] * (r - mid); lazy[k] = -1; } void update(int k,int l,int r,int L,int R,int v){ if(l >= L && r <= R){ tree[k] = v * (r - l + 1); lazy[k] = v; return ; } int mid = (l + r) >> 1; if(mid >= R){ update(k << 1,l,mid,L,R,v); }else if(mid < L){ update(k << 1 | 1,mid + 1,r,L,R,v); }else{ update(k << 1,l,mid,L,R,v); update(k << 1 | 1,mid + 1,r,L,R,v); } tree[k] = tree[k << 1] + tree[k << 1 | 1]; } int query(int k,int l,int r,int L,int R){ if(l >= L && r <= R){ return tree[k]; } if(lazy[k] != -1){ push_down(k,l,r); } int mid = (l + r) >> 1; if(mid >= R){ return query(k << 1,l,mid,L,R); }else if(mid < L){ return query(k << 1 | 1,mid + 1,r,L,R); }else{ return query(k << 1,l,mid,L,R) + query(k << 1 | 1,mid + 1,r,L,R); } } int main(){ IOS; int t,n,q,l,r; cin>>t; while(t --){ cin>>n>>q; cin>>(s1 + 1)>>(s2 + 1); build(1,1,n); bool ans = true; rep(i,1,q) cin>>nd[i].l>>nd[i].r; per(i,q,1){ l = nd[i].l,r = nd[i].r; if(!ans) continue; int num1 = query(1,1,n,l,r); int num0 = r - l + 1 - num1; if(num0 == num1){ ans = false; break; } update(1,1,n,l,r,num0 < num1); } rep(i,1,n) if(query(1,1,n,i,i) != s1[i] - '0'){ ans = false; break; } cout<<(ans?"YES":"NO")<<endl; } return 0; }
F. Nezzar and Nice Beatmap
Problem:
给你 n 个点,问你能否进行重新排序,使得任意相邻的三个点之间所构成的夹角为锐角,可以的话请输出第 i 个点是原序列中的第几个点?
Solution:
由于在三角形中,只有最长边对应的角可能是钝角,所以我们首先任意选取一个点,在剩下点中,每次我们都选取最长边的点。这样就可以避免出现当前点(p1)连接一个点(p2)之后,p2 再连接 p3,而| p1,p2 | < | p1,p3 |,若出现| p1,p2 | < | p1,p3 |,那么对于角p1,p2,p3来说就是一个钝角。
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define _for(i,s,t) for(int i=s;i<t;i++) #define _rof(i,s,t) for(int i=s;i>t;i--) #define rep(i,s,t) for(int i=s;i<=t;i++) #define per(i,s,t) for(int i=s;i>=t;i--) #define Ri(x) scanf("%d",&x) #define Rii(x,y) scanf("%d%d",&x,&y) #define INF 0x3f3f3f3f using namespace std; template<class T>inline void read(T &res) { char c;T flag=1; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; } typedef long long ll; const int maxn = 5e3 + 10; struct Node{ ll x,y; }nd[maxn]; bool selected[maxn]; ll dis(int i,int j){ return (nd[i].x - nd[j].x) * (nd[i].x - nd[j].x) + (nd[i].y - nd[j].y) * (nd[i].y - nd[j].y); } int main(){ IOS; int n; cin>>n; rep(i,1,n){ cin>>nd[i].x>>nd[i].y; } ll mx; int nowSelect = 1,lastSelect = 1; selected[1] = true; cout<<nowSelect<<" "; rep(i,2,n){ mx = -1e18; rep(j,1,n){ if(!selected[j] && mx < dis(lastSelect,j)){ mx = dis(lastSelect,j); nowSelect = j; } } selected[nowSelect] = true; cout<<nowSelect<<" "; lastSelect = nowSelect; } return 0; }
补题 C、D、E、F、G
ps:一列一列的观察