组题2

Posted on 2022-03-14 20:07  Capterlliar  阅读(48)  评论(0编辑  收藏  举报

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;
}
View Code

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
View Code

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;
}
View Code

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
View Code

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;
}
View Code