0%

思路讲解

就是暴力枚举一下就行了。当然要预处理一下。

AC代码

https://acm.hdu.edu.cn/contest/view-code?cid=1172&rid=25007

心路历程(WA,TLE,MLE……)

思路讲解

首先根据容斥原理,并集=全集-交集。

1
2
3
4
FOR(i,1,N){
ll ans=rka[i]+rkb[i]-2-jiao[i];
cout<<ans<<" ";
}

那么问题就来到了如何求这个交集。那么我们排列(首先根据rka)以后,只有前面的才有可能是在这个交集之中。

1
2
3
4
5
FOR(i,1,N){
ele.EB(rka[i],rkb[i],0);
ele.EB(rka[i],rkb[i],1);
}
sort(all(ele));

那么问题就来到了有几个jj,使得 rkbj<rkbirkb_j<rkb_i 了,这个可以用树状数组解决(类似于逆序对,我们只用考虑前面的比我们大的数字,这里我们也只用考虑前面的,因为后面 rkarka 不满足)。

1
2
3
4
5
6
7
8
for(auto &[x,y,isq]:ele){
ll a=A[x];
if(isq){
jiao[a]=tr.query(1,y-1);
}else{
tr.add(y,1);
}
}

AC代码

https://acm.hdu.edu.cn/contest/view-code?cid=1173&rid=10158

心路历程(WA,TLE,MLE……)

思路讲解

不难发现,这个x坐标完全取决于奇数操作,y坐标完全取决于偶数操作。

在y有y个操作下,其可以产生 [y+1,2y][y+1,2^{y}] 种子集和(就是这个范围内的都能生成)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FOR(i,1,N){
if(i*i>N) break;
if(N%i==0){
ll di=N/i;
FOR(j,1,N){
ll y=j/2,x=(j+1)/2;
if(binpow(2,y)>N) break;
if(i>=x && i<=binpow(2,x-1) && di<=binpow(2,y) && di>=y+1){
ans=min(ans,j);
}
if(di>=x && di<=binpow(2,x-1) && i<=binpow(2,y) && i>=y+1){
ans=min(ans,j);
}
}
}
}

AC代码

心路历程(WA,TLE,MLE……)

思路讲解

三个集合的容斥原理

$\left | A \cup B \cup C \right | = \left | A \right | + \left | B \right | + \left | C \right | - \left | A \cap B \right | - \left | A \cap C \right | - \left | B \cap C \right | + \left | A \cap B \cap C \right | $

image

那么不难发现规律,就是奇加偶减。这就是这段代码的由来。

1
2
3
ll cn=bi.count();
if(cn%2==1) del+=(sz+1)*sz/2;
else del-=(sz+1)*(sz)/2;

那么直接计算合法路径数量比较难,但是我们可以枚举不合法子集。如果s是101(二进制),那么就是第一个素因子要不符合要求(LCM只关注这些数当中的最大的,你可以理解为对素因子取了一个并集,那么gcd就是取了一个交集)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// s如果这一位是1,就代表这一位的质因数必须不满足要求
FOR(s,0,(1<<siz)-1){
vb vis(N+5,0);
bitset<11> bi(s);
// 检查该数字(该点)是否满足要求
auto check=[&](ll u)->bool{
FOR(i,0,siz-1){
if(!bi[i]) continue;
// 该数不满足要求,因为我们要求这一位质因数数量缺失,或者太多
if(fach[u][i]==cnt[i]){
return false;
}
}
return true;
};
FOR(u,1,N){
if(vis[u]) continue;
if(!valid[u]) continue;
vis[u]=true;
if(!check(u)) continue;
queue<ll> q;q.push(u);
ll sz=0; // 维护联通块内的点的数量
while(!q.empty()){
ll u=q.front();q.pop();
vis[u]=true;
++sz;
for(auto v:g[u]){
if(vis[v]) continue;
if(!valid[v]) continue;
if(!check(v)) continue;
q.push(v);
}
}
// sz*(sz-1)/2+sz
ll cn=bi.count();
if(cn%2==1) del+=(sz+1)*sz/2;
else del-=(sz+1)*(sz)/2;
// ans+=(sz+1)*sz/2;
}
#ifdef LOCAL
debug(del);
#endif
}
ll ans=-del;
cout<<ans<<"\n";
}

AC代码

https://acm.hdu.edu.cn/contest/view-code?cid=1172&rid=22776

心路历程(WA,TLE,MLE……)

思路讲解

那么容易想到,按照x排序,可以让sumx最大的方式就是排序,然后左边匹配右边。

而且,这样子匹配,左边的谁匹配右边的谁也是不重要的,至少对于sumx不重要,因此我们就可以按照使sumy最大的方式进行匹配。

同理,计算按照y排列能得到的答案即可。

AC代码

https://codeforces.com/contest/2122/submission/329811774

心路历程(WA,TLE,MLE……)