A层2
不知道拖了多久,我太菜了
A Coprime Arrays
完全没有想到会考莫反
形式化一下
\(\displaystyle f(k) = \sum_{a_1 = 1}^{k}\sum_{a_2 = 1}^{k}... [gcd == 1]\)
套路莫反得到
\(\displaystyle f(k) = \sum_{d = 1}^{k}\mu(d)\lfloor \frac{k}{d} \rfloor\)
然后发现 \(\lfloor \frac{k}{d} \rfloor != \lfloor \frac{k + 1}{d} \rfloor\) 时 $ d | (k + 1)$, 这样就能简单维护了
code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2000005;
const int mod = 1e9 + 7;
int n, k, cnt, prime[maxn], mu[maxn], po[maxn];
bool flag[maxn];
int qpow(int x, int y){
int ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1) ans = 1ll * ans * x % mod;
return ans;
}
vector<int>p[maxn];
int main(){
scanf("%d%d",&n,&k);
mu[1] = 1;
for(int i = 2; i <= k; ++i){
if(!flag[i])prime[++cnt] = i, mu[i] = -1;
for(int j = 1; j <= cnt && i * prime[j] <= k; ++j){
flag[i * prime[j]] = 1;
if(i % prime[j] == 0)break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1; i <= k; ++i)po[i] = qpow(i, n);
for(int i = 1; i <= k; ++i)if(mu[i])
for(int j = i; j <= k; j += i)p[j].push_back(i);
int now = 0, ans = 0;
for(int i = 1; i <= k; ++i){
for(int v : p[i]){
now = now - mu[v] * (po[(i - 1) / v] - po[i / v] + mod) % mod;
now = (now % mod + mod) % mod;
}
ans = (ans + (now xor i)) % mod;
}
printf("%d\n",ans);
return 0;
}
B Werewolves
分颜色处理,处理某个颜色时,该颜色结点权值为 \(1\) ,其他的为 \(-1\)
一个联通块有贡献,当且仅当其权值和大于 \(0\)
那么再回来看这个问题,就可以看做树形背包
每次合并一个子树的信息即可,注意这里需要有负的权值,所以我给数组下标都加上一个 \(base\)
code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3005;
const int mod = 998244353;
const int base = 3002;
int n, m, ans, col[maxn], val[maxn], f[maxn][maxn + maxn];
bool del[maxn];
vector<int>g[maxn];
int size[maxn], fa[maxn], tmp[maxn + maxn];
void pre(int x){
size[x] = 1;
for(int v : g[x]){
if(v == fa[x])continue;
fa[v] = x; pre(v);
size[x] += size[v];
}
}
void dfs(int x){
if(val[x] == 1)f[x][base + 1] = 1;
else f[x][base - 1] = 1;
int ns = 1;
for(int v : g[x]){
if(v == fa[x])continue;
dfs(v);
for(int i = - min(ns, m); i <= min(ns, m); ++i)tmp[i + base] = f[x][i + base];
for(int i = - min(ns, m); i <= min(ns, m); ++i)
for(int j = -min(size[v], m); j <= min(size[v], m); ++j)
if(i + j >= -m && i + j <= m)f[x][base + i + j] = (f[x][base + i + j] + 1ll * tmp[i + base] * f[v][j + base] % mod) % mod;
ns += size[v];
}
for(int i = 1; i <= min(size[x], m); ++i)ans = (ans + f[x][i + base]) % mod;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i)scanf("%d",&col[i]);
for(int i = 1; i < n; ++i){
int u, v; scanf("%d%d",&u, &v);
g[u].push_back(v); g[v].push_back(u);
}
pre(1);
for(int i = 1; i <= n; ++i){
if(del[col[i]])continue;
del[col[i]] = 1; m = 0;
for(int j = 1; j <= n; ++j){
val[j] = col[j] == col[i] ? 1 : -1;
m += col[j] == col[i];
}
for(int j = 1; j <= n; ++j)
for(int k = -m; k <= m; ++k)
f[j][k + base] = 0;
dfs(1);
}
printf("%d\n",ans);
return 0;
}