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