A - Zero Array
题意:给出一组数,每次挑两个减1,问能否在若干次操作之后使得数组全为0.
解:首先它们的和要是偶数,其次如果有一个太大了那也减不完,太大的标准是超过总和的一半。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 1000000007 #define base 2333 //#define int long long int n; int a[maxx]; signed main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); ll sum=0; int m=0; for(int i=1;i<=n;i++){ sum+=a[i]; m=max(m,a[i]); } if(sum%2==0&&sum>=m*2) printf("YES\n"); else printf("NO\n"); return 0; }
B - Same GCDs
题意:给出两个数a和m,计算共有几个x使得gcd(a,m)=gcd(a+x,m),其中0<=x<m。
解:令gcd(a,m)=d,也就是gcd((a+x)/d,m/d)=1,也就是gcd((a+x-m)/d,m/d)=1,欧拉函数。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 100005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 1000000007 #define base 2333 //#define int long long ll n,a,m; ll phi(ll n){ ll res = n; for (ll i = 2; i * i <= n; i++){ if (n % i == 0) res = res / i * (i - 1); while (n % i == 0) n /= i; } if (n > 1) res = res / n * (n - 1); return res; } ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } signed main() { int T; scanf("%d",&T); while(T--){ scanf("%lld%lld",&a,&m); ll d=gcd(a,m); printf("%lld\n",phi(m/d)); } return 0; } // 30 100 // 2 3 5 // 2 2 5 5 // 2 5
C - Multiset
题意:给出一组数,每次或选出排名第k的数删除,或加入数x,最后输出任意一个在mutiset中的元素,如果mutiset为空,则输出0.
解:权值线段树+二分。把排名第k看成第k大还WA了一发。。。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 1000005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 100000000 #define mod 1000000007 #define base 2333 //#define int long long int n,q; int a[maxx],tr[maxx*4]={0}; void add(int now,int l,int r,int pos){ if(l==r){ tr[now]++; return; } int mid=(l+r)/2; if(pos<=mid) add(now*2,l,mid,pos); if(mid<pos) add(now*2+1,mid+1,r,pos); tr[now]=tr[now*2]+tr[now*2+1]; } int del(int now,int l,int r,int k,int sum){ if(l==r){ tr[now]--; return l; } int mid=(l+r)/2; int res=0; if(k<=sum+tr[now*2]) res=del(now*2,l,mid,k,sum); else if(k<=sum+tr[now]) res=del(now*2+1,mid+1,r,k,sum+tr[now*2]); tr[now]=tr[now*2]+tr[now*2+1]; return res; } signed main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) add(1,1,maxx,a[i]); int opt; for(int i=1;i<=q;i++){ scanf("%d",&opt); if(opt<0) del(1,1,maxx, abs(opt),0); else add(1,1,maxx,opt); } printf("%d\n", del(1,1,maxx,1,0)); return 0; }
D - Thanos Nim
题意:给出n堆石头,n为偶数,Alice和Bob每次选出一半的堆从中取走至少一块石头,最后当n/2以上堆为空时,这轮行动的一方输掉,Alice先手,问谁能赢,
解:好玩的题。首先考虑什么局面必胜或必败。显然当全是1的时候,这一轮的人必败。考虑以下情况:当1少于等于一半的时候,例如111122,这轮的人一定会使它变成110011,这样必胜;反之,当1多余一半时必败。考虑没有1的情况:222222,也是必败态,同理,2少于等于一半时必胜。因此结论就变成了:当最小值个数小于等于一半时必胜,反之必败。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 100005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 100000000 #define mod 1000000007 #define base 2333 //#define int long long int n,a[100],m; signed main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); int minn=inf,cnt=0; for(int i=1;i<=n;i++) minn=min(minn,a[i]); for(int i=1;i<=n;i++){ if(a[i]==minn) cnt++; } if(cnt<=n/2) printf("Alice\n"); else printf("Bob\n"); return 0; } // 1>=half win // 1<half lose // 1 can be the smallest
F - Shortest Cycle
题意:给出一组数,对于任意ai,aj,如果 ai&aj != 0 ,那么它们之间有一条无向边。求这张图里最小环的长度。
解:题中每个数长度不超过1018,也就是64位,按位拆的话根据抽屉原理,一旦有129个非零数就一定能形成一个长位3的环,它最小。那么接下来就要考虑两两连边的情况,显然不会超过128个点,暴力跑floyd最小环就行了。注意3倍inf不要爆int。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 100005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 100000000 #define mod 1000000007 #define base 2333 //#define int long long ll n,a[maxx],m; int dis[200][200]={0},f[200][200]={0}; int point[maxx]={0}; signed main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); int cnt=0; for(int i=1;i<=n;i++){ if(a[i]) point[++cnt]=i; } if(cnt>130){ printf("3\n"); return 0; } int ans=inf; for(int i=1;i<=cnt;i++){ for(int j=1;j<=cnt;j++){ if(i==j) continue; if(a[point[i]]&a[point[j]]) { dis[i][j] = dis[j][i] = 1; f[i][j] = f[j][i] = 1; } else{ dis[i][j] = dis[j][i] = inf; f[i][j] = f[j][i] = inf; } } } for(int k=1;k<=cnt;k++){ for(int i=1;i<k;i++) for(int j=i+1;j<k;j++) ans = min(ans,dis[i][j]+f[i][k]+f[k][j]); for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++){ dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]); dis[j][i] = dis[i][j]; } } if(ans==inf) printf("-1\n"); else printf("%d\n",ans); return 0; }