AtCoder Beginner Contest 206(Sponsored by Panasonic)题解

本场链接:AtCoder Beginner Contest 206(Sponsored by Panasonic)

D - KAIBUNsyo

不难想到直接找到每对不合法的元素,由于替换操作是对所有元素执行的,所以考虑以此构造图。每次操作可以将一个图上的一条边删去,求消除所有图的删除代价就是最小操作数,即对连通分量大小\(-1\)求和即答案。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 2e5+7,M = 2 * N;
int edge[M],succ[M],ver[N],idx;
int a[N];
bool st[N];

void add(int u,int v)
{
    edge[idx] = v;
    succ[idx] = ver[u];
    ver[u] = idx++;
}

void dfs(int u,int& sz)
{
    st[u] = 1;++sz;
    for(int i = ver[u];~i;i = succ[i])
    {
        int v = edge[i];
        if(st[v])   continue;
        dfs(v,sz);
    }
}

int main()
{
    memset(ver,-1,sizeof ver);
  	int n;scanf("%d",&n);
    forn(i,1,n) scanf("%d",&a[i]);
    forn(i,1,n) if(a[i] != a[n - i + 1])    add(a[i],a[n - i + 1]);
    int res = 0;
    forn(i,1,N - 1) if(!st[i])  {int sz = 0;dfs(i,sz);res += sz - 1;}
    printf("%d\n",res);
    return 0;
}

E - Divide Both

问题转换为求:对于每个\(x\in[l,r]\)求在\([x+1,r]\)区间中与\(x\)互质或者是\(x\)倍数的数。后者显然,考虑前者:直接考虑互质做不了,只有再转一次考虑计算\(gcd=k\in[2,r]\)的所有情况,再挖掉这些情况得到互质的个数。考虑容斥,由于与质因数相关不难想到容斥系数就是\(u(x)\).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 1e6+7;
int primes[N],mob[N],cnt;
bool st[N];

void init()
{
    mob[1] = 1;
    for(int i = 2;i < N;++i)
    {
        if(!st[i])  primes[cnt++] = i,mob[i] = -1;
        for(int j = 0;j < cnt && primes[j] * 1ll * i < N;++j)
        {
            int t = primes[j] * i;
            st[t] = 1;
            if(i % primes[j] == 0)
            {
                mob[t] = 0;
                break;
            }
            mob[t] = mob[i] * -1;
        }
    }
}


int main()
{
    init();
    int L,R;scanf("%d%d",&L,&R);
    ll res = 0;
    forn(i,2,R)
    {
        ll A = (R / i) - (L - 1) / i;
        res -= mob[i] * A * 1ll * (A - 1) / 2;
    }
    forn(i,max(2,L),R)  res -= R / i - 1;
    res *= 2;
    printf("%lld\n",res);
    
    return 0;
}

F - Interval Game 2

把过程看作是在一个大区间上去选一些区间:一开始是\([1,100)\),当A选走了\([x,y)\)之后,区间会被划分成\([1,x)\)\([y,100)\)两个子区间。即一个大游戏划分成了两个小游戏,SG定理即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
#define x first
#define y second

const int N = 105;
int f[N][N];
vector<pii> seg;

int sg(int l,int r)
{
    if(l >= r)  return 0;
    if(~f[l][r])    return f[l][r];
    vector<bool> kth(N - 1,0);
    for(auto& s : seg)  if(l <= s.x && s.y <= r)    kth[sg(l,s.x) ^ sg(s.y,r)] = 1;
    forn(i,0,N - 1) if(!kth[i]) {f[l][r] = i;break;}
    return f[l][r];
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        forn(i,0,N - 1) forn(j,0,N - 1) f[i][j] = -1;
        int n;scanf("%d",&n);
        seg.clear();
        forn(i,0,n - 1)
        {
            int l,r;scanf("%d%d",&l,&r);
            seg.push_back({l,r});
        }        
        if(sg(1,100))   puts("Alice");
        else puts("Bob");
    }
    return 0;
}

posted @ 2021-06-24 10:23  随处可见的阿宅  阅读(108)  评论(0编辑  收藏  举报