Gym102896F Find a Square
题目描述:给定正整数 (a,b,c,n),设 (f(k)=ak^2+bk+c),求 (prod_{k=0}^{n-1}f(k)) 的最大平方因子(mod(10^9+7))。
数据范围:(a,b,c,nle 6cdot 10^5)。
solution
质因子 (p^e) 对答案的贡献是 (p^{e-emod 2}),因此不需要考虑 (e=1) 的情况。
对于一个质数 (p),考虑如何求出其指数。当 (p|2a) 时直接暴力,这样的素数只有 (omega(2a)) 个。
当 (pot 2a) 时,可以求出 (ak^2+bk+cequiv0pmod p) 的根,这样的根在模意义下至多只有两个,因此总共至多有 (lceilfrac{2n}p ceil) 个。
问题就转化为如何找到这些质数。若要判 (m) 个则时间复杂度为 (O(mlog p))。
首先判掉 (le1222222) 的所有质数,之后每个 (f(k)) 至多剩下两个质因子。只用考虑至少整除其中两个数的质数 (p),即存在 (x,y) 使得 (p|gcd(f(x),f(y))=gcd(ax^2+bx+c,(x-y)(a(x+y)+b))),得到存在 (x<2n) 使得 (p|(ax+b)),用同样的方法筛出这些质数即可。
最后剩下的可能是平方数,再判一遍就可以了。
#include<bits/stdc++.h>
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef long double LD;
typedef __int128 LLL;
typedef pair<int, int> pii;
const int N = 1222222, mod = 1e9 + 7;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int a, b, c, n, tot, ans = 1; LL num[N], pri[N];
bool notp[N];
LL mul(LL a, LL b, LL p = mod){
LL d = (LL)((LD)a / p * b + 0.5);
LL r = a * b - p * d; return (r % p + p) % p;
}
LL ksm(LL a, LL b, LL p = mod){
LL res = 1;
for(;b;b >>= 1, a = mul(a, a, p))
if(b & 1) res = mul(res, a, p);
return res;
}
void init(int m){
notp[0] = notp[1] = true;
for(int i = 2;i <= m;++ i){
if(!notp[i]) pri[tot++] = i;
for(int j = 0;j < tot && i * pri[j] <= m;++ j){
notp[i * pri[j]] = true;
if(!(i % pri[j])) break;
}
}
} LL i2, pr;
struct comp {
LL x, y;
comp(LL _x = 0, LL _y = 0): x(_x), y(_y){}
comp operator * (const comp &o) const {
return comp((mul(x, o.x, pr) + mul(mul(y, o.y, pr), i2, pr)) % pr, (mul(x, o.y, pr) + mul(y, o.x, pr)) % pr);
} comp operator *= (const comp &o){*this = *this * o; return *this;}
};
LL Cipolla(LL x, LL p){
if(!x) return 0;
if(ksm(x, p-1>>1, p) != 1) return -1;
if((p & 3) == 3) return ksm(x, p+1>>2, p);
LL a = 1;
while(true){
i2 = (mul(a, a, p) + p - x) % p;
if(ksm(i2, p-1>>1, p) != 1) break; ++ a;
} comp tt(a, 1), res(1); pr = p;
for(LL b = p+1>>1;b;b >>= 1, tt *= tt) if(b & 1) res *= tt;
return res.x;
}
int main(){
read(a); read(b); read(c); read(n); init(N-1);
for(int k = 0;k < (n<<1);++ k) num[k] = (LL)a * k + b;
for(int i = 0;i < tot;++ i){
LL p = pri[i];
if(!(a % p)) for(int j = 0;j < (n<<1);++ j)
while(!(num[j] % p)) num[j] /= p;
else for(int j = (p - b % p) * ksm(a % p, p-2, p) % p;j < (n<<1);j += p)
while(!(num[j] % p)) num[j] /= p;
} for(int k = 0;k < (n<<1);++ k) if(num[k] > 1) pri[tot++] = num[k];
sort(pri, pri+tot); tot = unique(pri, pri+tot) - pri;
for(int k = 0;k < n;++ k) num[k] = ((LL)a * k + b) * k + c;
LL delta = (LL)b * b - 4ll * a * c;
for(int i = 0;i < tot;++ i){
LL p = pri[i], cnt = 0;
if(!((a<<1) % p)) for(int j = 0;j < n;++ j)
while(!(num[j] % p)){num[j] /= p; ++ cnt;}
else {
LL Sqr = Cipolla((delta % p + p) % p, p);
if(Sqr == -1) continue;
LL inv = ksm((a<<1) % p, p-2, p);
LL val = mul((Sqr + p - b % p) % p, inv, p);
for(LL j = val;j < n;j += p)
while(!(num[j] % p)){num[j] /= p; ++ cnt;}
val = mul((p - (Sqr + b) % p) % p, inv, p);
for(LL j = val;j < n;j += p)
while(!(num[j] % p)){num[j] /= p; ++ cnt;}
} ans = ans * ksm(p % mod, cnt - (cnt & 1)) % mod;
}
for(int k = 0;k < n;++ k){
LL Sqr = sqrt(num[k]);
for(LL i = max(Sqr-1, 0ll);i <= Sqr+1;++ i)
if(i * i == num[k]) ans = num[k] % mod * ans % mod;
} printf("%d
", ans);
}
*CF1383F Special Edges
题目描述:给定 (n) 个点 (m) 条边的无向图,(k) 条是特殊边,非特殊边有给定容量。(q) 次查询给定特殊边的容量,求 (1 ightarrow n) 的最大流。
数据范围:(n,mle 10^4,kle 10,qle 2cdot10^5,wle 25)。
solution
考虑转化成最小割,钦定每条特殊边是否被割,然后跑最大流。直接暴力是过不去的。要优化一下。
首先用 Dinic 在原图上跑出残余网络,然后钦定一条边没被割就是加一条边权为 (+infty) 的边。
将 (2^k) 个残余网络存下来,维护加一条边跑网络流可以使用 FF 算法,即暴力找一条增广路然后增广。
时间复杂度 (O((wm+q)2^k))。空间也要卡一卡...然后就懒得写了...
*CF1393E Twilight and Ancient Scroll
题目描述:给定 (n) 个字符串 (s_i),求对每个字符串,可以删除一个字符或保持原样,使得这些字符串的字典序单调不降的方案数。
数据范围:(nle 10^5,sum |s_i|le 10^6)。
solution
对每个字符串的所有方案排序,很容易做到 (O(sum|s_i|log|s_i|))。
然后直接 dp,时间复杂度 (O(sum|s_i|))。这就是 3200 么...
*CF1214G Feeling Good
题目描述:给定 (n imes m) 的 01 矩阵 (M),初始时全 0,每次操作给定 (a,l,r) 表示 (forall iin[l,r]) 将 (M_{a,i}) 反转,并求出一个左上角为 ((x_1,y_1)),右下角为 ((x_2,y_2)) 的子矩形,使得
- (1le x_1<x_2le n,1le y_1<y_2le m)。
- 矩阵的四个角,同侧不同,对角相同。
需判断无解。
数据范围:(n,mle 2000,qle 5cdot 10^5)。
壬被玩傻了
solution
用 bitset 维护每一行,设第 (i) 行 (1) 的位置集合是 (S_i),只需找到两行 (i,j) 使得 (S_i,S_j) 互不包含即可。
小性质:按集合大小排序之后,(forall i<j<k),(S_i,S_k) 互不包含 (Rightarrow) (S_i,S_j) 互不包含或 (S_j,S_k) 互不包含。
于是用 set 维护 (1) 的个数的大小关系,用 bitset 判断两行间包含关系即可。
复杂度 (O(frac{m(n+q)}w+qlog n))(甚至还挺小...)
*CF1214H Tiles Placement
题目描述:给定 (n) 个点的树和正整数 (k),求给点染 (k) 种颜色的方案,使得任意一条点数为 (k) 的简单路径有 (k) 种颜色。需判断无解。
数据范围:(2le kle nle 2cdot10^5)。
solution
奇怪结论题...
首先特判 (k=2),这个二分图染色即可。考虑 (k>2) 的情况。
手玩一下可以发现,如果有三个点 (u,v,w) 两两距离 (ge k-1),则无解。
然后就可以构造了,求出直径,判一下有解条件,此时任意点数为 (k) 的简单路径都会经过直径中点,从这个点开始 dfs 染色即可。时间复杂度 (O(n))。
*CF1220G Geolocation
题目描述:给定平面上 (n) 个天线 ((x_i,y_i))。(m) 次询问 (d_1,d_2,dots,d_n),表示某个位置 ((x,y)) 到每个天线距离的平方排序之后的数组,求所有可能的整点 ((x,y)),保证有解。
数据范围:(nge 2,nmle 10^5,x_i,y_ile 10^8)。所有输入数据都是非负整数。用于生成数据的 (x,y) 在 ([0,10^8]capN) 中独立均匀随机生成。
solution
经典结论:若将这 (n) 个点的重心作为原点,则 (x^2+y^2=frac{sum d_i^2-sum_{i=1}^n(x_i^2+y_i^2)}n)。
然后枚举 ((x,y)) 到 ((x_1,y_1)) 的距离,求出圆交点并暴力 Check。因为数据随机所以复杂度是对的?
精度误差可能很要死,建议手写个高精分数类并精细实现。
*CF1220F Gardener Alex
题目描述:给定长为 (n) 的排列 (a),求所有循环移位中小根笛卡尔树的最小深度及取到最小值的方案。
数据范围:(nle 2cdot 10^5)。
solution
降智大赛?
先倍长成链,容易知道每个元素在笛卡尔树上的子树区间是不变的,求出这个区间,深度即为每个元素被覆盖的次数的最大值。用线段树维护区间加,区间求 (max) 即可。
*CF1223G Wooden Raft
题目描述:给定 (n) 个姜米條,你可以切割姜米條但不能拼起来。求在所有切割出两个 (x) 和 (x) 个 (y) 的方案中 (x imes y) 的最大值。
数据范围:(n,a_ile 5cdot 10^5)。
solution
枚举 (y),分类讨论两个 (x) 在同一块还是不同块,然后枚举 (lfloorfrac{2x}y floor) 或 (lfloorfrac xy floor)。
时间复杂度 (O(n+Vlog V))。
CF1225G To Make 1
题目描述:给定 (n) 个正整数 (a_i) 和正整数 (k),定义
每次操作取出两个正整数 (x,y),加入 (f(x+y)),构造使最终剩下 (1) 的方案,需判断无解。
数据范围:(2le nle 16,2le k,sum a_ile 2000,k mid a_i)。
神仙状压
solution
结论:解存在当且仅当存在 (n) 个非负整数 (b_i) 使得 (1=sum_{i=1}^na_ik^{-b_i})。
证明:(Rightarrow) 显然,(Leftarrow) 考虑归纳,易得 (b) 中最大值所对应的 (a_i) 之和被 (k) 整除,把最大值合并即可。
于是就可以状压 dp 了,设 (f_{S,x}) 表示存在一组 (b) 使得 (sum_{iin S}a_ik^{-b_i}=x)。转移即按照 (S) 从小到大,(x) 从大到小的顺序,(f_{S,x}=f_{S,kx}lor f_{Sackslash{a_i},x-a_i})。
构造方案即求出 (b_i) 再按照从大到小的顺序合并即可。时间复杂度 (O(frac{n2^nsum a_i}w))。
#include<bits/stdc++.h>
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 1<<16, M = 2003;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int n, k, lim, a[16], sum, b[16];
bitset<M> f[N]; priority_queue<pii> pq;
int main(){
read(n); read(k); lim = 1<<n; f[0][0] = 1;
for(int i = 0;i < n;++ i){read(a[i]); sum += a[i];}
for(int S = 1;S < lim;++ S){
for(int i = 0;i < n;++ i) if(S >> i & 1) f[S] |= f[S ^ (1<<i)] << a[i];
for(int i = sum / k;i;-- i) if(f[S][i*k]) f[S][i] = 1;
} if(!f[lim-1][1]){puts("NO"); return 0;}
puts("YES"); int S = lim-1, x = 1;
while(S){
for(;x*k <= sum && f[S][x*k];x *= k)
for(int i = 0;i < n;++ i) if(S >> i & 1) ++ b[i];
for(int i = 0;i < n;++ i)
if(x >= a[i] && (S >> i & 1) && f[S ^ (1<<i)][x - a[i]]){S ^= 1<<i; x -= a[i]; break;}
}
for(int i = 0;i < n;++ i) pq.push(MP(b[i], a[i]));
while(pq.size() > 1){
pii p = pq.top(); pq.pop(); pii q = pq.top(); pq.pop();
printf("%d %d
", p.se, q.se); p.se += q.se;
while(!(p.se % k)){p.se /= k; -- p.fi;} pq.push(p);
}
}
-CF1237G Balanced Distribution
题目描述:给定正整数 (k) 和排成环形,按顺时针编号为 (0,1,dots,n-1) 的非负整数 (a_i)。每次操作可以选择相邻 (k) 个数进行修改,要求其总和不变。求使得所有 (a_i) 相等的最小操作次数及方案。
数据范围:(2le k<nle 10^5,a_ile 10^4,n|sum a_i)。
CF1237H Balanced Reversals
题目描述:给定长为 (n) 的 01 字符串 (S,T),每次操作选择 (S) 的一个长度为偶数的前缀翻转,构造至多 (n+1) 次操作将 (S) 变为 (T),需判断无解。(T) 组数据。
数据范围:(2|n,sum nle 4000)。
solution
首先将连续两个字符看做一个字符,一共四种字符 00,01,10,11。
显然有解的必要条件是 00 和 11 的个数相等。构造证明了它是必要条件。
首先要使 01 和 10 个数分别相等。选择 01 与 10 个数相差比较大的一个,然后翻转其某个前缀。
然后可以维护一段前缀 ([1,i]) 使得 ( ext{rev}(S[1:i])=T[1:i]),每次可以通过翻转两次前缀把 (S[1:j]) 向右循环移位。最后翻转 ([1,n-2]) 即可。总操作次数为 (2(frac n2-1)+2=n)。
#include<bits/stdc++.h>
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 2003;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int T, n, m, a[N], b[N], c[4], d[4], ans[N], tot;
char s1[N<<1], s2[N<<1];
void rev(int *a, int k){
for(int i = (k>>1);i;-- i) swap(a[i], a[k-i+1]);
for(int i = 1;i <= k;++ i) if(a[i] <= 1) a[i] ^= 1;
}
int enc(char x, char y){if(x == '0') return y == '0' ? 2 : 0; return y == '0' ? 1 : 3;}
void solve(){
scanf("%s%s", s1, s2); n = strlen(s1); m = n>>1;
memset(c, 0, sizeof c); memset(d, 0, sizeof d); tot = 0;
for(int i = 0;i < m;++ i){
++c[a[i+1] = enc(s1[i<<1], s1[i<<1|1])];
++d[b[i+1] = enc(s2[i<<1], s2[i<<1|1])];
} if(c[2] != d[2] || c[3] != d[3]){puts("-1"); return;}
int lst = -1;
if(c[0] != d[0]){
if(abs(c[0] - c[1]) > abs(d[0] - d[1])){
for(int i = 1;i <= m;++ i) if(a[i] <= 1){
-- c[a[i]]; ++ c[!a[i]];
if(c[0] == d[0]){rev(a, i); ans[++tot] = i; break;}
}
} else {
for(int i = 1;i <= m;++ i) if(b[i] <= 1){
-- d[b[i]]; ++ d[!b[i]];
if(c[0] == d[0]){rev(b, i); lst = i; break;}
}
}
}
for(int i = 1;i < m;++ i)
for(int j = i;j <= m;++ j)
if(a[j] == b[i]){
if(j > 1){rev(a, j-1); ans[++tot] = j-1;}
rev(a, j); ans[++tot] = j; break;
}
if(m > 1){rev(a, m-1); ans[++tot] = m-1;} if(~lst) ans[++tot] = lst;
printf("%d
", tot);
for(int i = 1;i <= tot;++ i) printf("%d ", ans[i]<<1); putchar('
');
}
int main(){read(T); while(T --) solve();}
CODE FESTIVAL 2016 Grand Final
*H AB=C Problem
题目描述:给定定义在 (mathbb F_2) 上的 (n imes n) 的矩阵 (C),求 ((A,B)) 的数量(mod(10^9+7)) 使得 (AB=C)。
数据范围:(nle 300)。
solution
好像是三年前的训练题,当时把人吓傻了。
容易得出,固定 (A) 之后,若 (A) 的列向量张成的线性空间包含 (C),则 (B) 的数量是 (2^{n(n- ext{rank}(A))})。
现在要对每个 (iin[1,n]) 求出有多少个矩阵 (A) 满足:
- (A) 张成的线性空间包含 (C)。
- ( ext{rank}(A)=i)。
设 (r= ext{rank}(C)),(f_{i,j}) 表示 (i) 个长为 (n) 的向量的秩大小为 (j) 的方案数,则 (A) 的数量为 (frac{f_{n,i}f_{i,r}}{f_{n,r}})。
CODE FESTIVAL 2017 qual B
F Largest Smallest Cyclic Shift
题目描述:给定非负整数 (x,y,z),构造字典序最大的字符串 (S) 使得其含有 (x) 个 a
,(y) 个 b
,(z) 个 c
,且在 (S) 的所有循环移位中 (S) 最小。
数据范围:(x+y+zle 50)。
solution
假设现在你有 (k) 个 Lyndon 串,要将其拼成一个字典序最大的幸运串。
根据 Lyndon 串的性质,对于所有拼成任意串的方法,循环移位中字典序最小的开头一定是组成其的 Lyndon 串的开头。
容易发现,字典序最小的串一定要放最前面。
容易发现,若 (S,T) 是 Lyndon 串且 (S<T),则 (S+T) 是 Lyndon 串。
若当前已有的这些串全相同,则直接全拼起来即可。
若当前已有的这些串不全相同,则直接把字典序最小的串拼上字典序最大的串,然后继续做下去,直到已有的这些串全相同。
使用 multiset 维护,时间复杂度 (O(n^2log n)),其中 (n=x+y+z),但是完全跑不满。
CF1017G The Tree
题目描述:给定 (n) 个点的树,点有黑白颜色,初始全白。(q) 次操作:给定点 (x),
- 若 (x) 为白色则染黑,否则对儿子递归做此操作。
- 将以 (x) 为根的子树染白。
- 查询 (x) 的颜色。
数据范围:(n,qle 10^5)。
solution
这题有至少两种做法,虽然我都不会
(O(nsqrt n)):考虑对询问分块,每一块对涉及到的点 (O(n)) 建虚树,并且处理出每条边上的白点和黑点个数。虚树上的暴力做,做完之后再推下去。代码简单极了...
(O(nlog^2n)):如果暴力做,复杂度偏向修改,考虑稍微平衡一下。
考虑 1 操作时单纯给点 (x) 的点权 +1,则操作 (x) 会影响子树中的点 (v) 当且仅当 ((x,v)) 这条路径上所有点的点权之和 (ge) ((x,v)) 的点数。若将初始点权设为 (-1) 则 (v) 是黑的当且仅当 ((rt,v)) 的最大后缀和 (ge 0)。可以用线段树维护。
然后考虑 2 操作,首先整棵子树的点权改为 (-1),然后要使子树外不对子树内有影响,还要将 (x) 减去某个值 (v) 使得 ((rt,x)) 的最大后缀和 (=-1),查询一次即可。
还是分块好(雾
#include<bits/stdc++.h>
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 100003, M = 1<<18;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int n, q, cnt, fa[N], head[N], to[N], nxt[N];
void add(int a, int b){to[++cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;}
int siz[N], wson[N], dep[N], dfn[N], tim, top[N];
void dfs1(int x){
siz[x] = 1;
for(int i = head[x];i;i = nxt[i]){
dep[to[i]] = dep[x] + 1; dfs1(to[i]);
siz[x] += siz[to[i]];
if(siz[to[i]] > siz[wson[x]]) wson[x] = to[i];
}
}
void dfs2(int x, int tp){
top[x] = tp; dfn[x] = ++tim;
if(!wson[x]) return; dfs2(wson[x], tp);
for(int i = head[x];i;i = nxt[i])
if(to[i] != wson[x]) dfs2(to[i], to[i]);
}
struct Node {
int sum, res;
Node(int s = 0, int r = -1e9): sum(s), res(r){}
Node operator + (const Node &o) const {return Node(sum + o.sum, max(o.res, res + o.sum));}
} seg[M];
bool tag[M];
void ptag(int x, int len){tag[x] = true; seg[x].sum = -len; seg[x].res = -1;}
void pdown(int x, int len){if(tag[x]){ptag(x<<1, len+1>>1); ptag(x<<1|1, len>>1); tag[x] = false;}}
void pup(int x){seg[x] = seg[x<<1] + seg[x<<1|1];}
Node qry(int l, int r, int x = 1, int L = 1, int R = n){
if(l <= L && R <= r) return seg[x];
int mid = L + R >> 1; pdown(x, R-L+1);
if(r <= mid) return qry(l, r, x<<1, L, mid);
if(mid < l) return qry(l, r, x<<1|1, mid+1, R);
return qry(l, r, x<<1, L, mid) + qry(l, r, x<<1|1, mid+1, R);
}
void upd(int p, int v, int x = 1, int L = 1, int R = n){
if(L == R){seg[x].sum += v; seg[x].res += v; return;}
int mid = L + R >> 1; pdown(x, R-L+1);
if(p <= mid) upd(p, v, x<<1, L, mid);
else upd(p, v, x<<1|1, mid+1, R); pup(x);
}
void cov(int l, int r, int x = 1, int L = 1, int R = n){
if(l <= L && R <= r){ptag(x, R-L+1); return;}
int mid = L + R >> 1; pdown(x, R-L+1);
if(l <= mid) cov(l, r, x<<1, L, mid);
if(mid < r) cov(l, r, x<<1|1, mid+1, R); pup(x);
}
int qry(int x){
Node res;
while(top[x] > 1){res = qry(dfn[top[x]], dfn[x]) + res; x = fa[top[x]];}
return (qry(1, dfn[x]) + res).res;
}
int main(){
read(n); read(q); ptag(1, n);
for(int i = 2;i <= n;++ i){read(fa[i]); add(fa[i], i);}
dfs1(1); dfs2(1, 1);
while(q --){
int opt, x; read(opt); read(x);
if(opt == 1) upd(dfn[x], 1);
else if(opt == 2){
cov(dfn[x], dfn[x] + siz[x] - 1);
upd(dfn[x], - qry(x) - 1);
} else puts(qry(x) >= 0 ? "black" : "white");
}
}
-CF1028F Make Symmetrical
题目描述:维护 (Ssubseteq {1,2,dots,112904}^2),(q) 次操作给定 (x,y):
- (S) 中加入 ((x,y)),保证操作前 ((x,y) otin S)。
- (S) 中删去 ((x,y)),保证操作前 ((x,y)in S)。
- 求至少需添加多少点才能使得 (S) 关于 ((0,0),(x,y)) 连线对称。询问不加点且独立。
数据范围:(qle 2cdot 10^5)。
CF1205E Expected Value Again
题目描述:给定字符串长度 (n) 和字符集大小 (k),设 (X) 为 border 个数(不含本身),求 (mathbb E[X^2]mod(10^9+7))。
数据范围:(nle 10^5,kle 10^9)。
solution
长度为 (x) 的 border 等价于 (n-x) 的非严格周期。
显然只能钦定两个循环节 (p,q) 算方案数。
Periodicity Lemma
若字符串 (S) 有循环节 (p,q),且 (p+qle |S|+gcd(p,q)),则 (gcd(p,q)) 也是循环节。
考虑一个样例 (S=) abacaba
,(p=6,q=4),而 (gcd(p,q)=2) 不是循环节,所以下界是紧的。
证:不妨设 (p>q) 且下标从 (1) 开始。
考虑归纳,奠基显然成立。
对于 (ile |S|-p),有 (S_i=S_{i+p}=S_{i+p-q}),所以 (p-q) 是长度为 (|S|-q) 的前缀的循环节,后缀同理。
因为 ((p-q)+qle(|S|-q)+gcd(p-q,q)),根据归纳可知 (gcd(p,q)) 是长度为 (|S|-q) 的前缀的循环节,后缀同理。
因为 (gcd(p,q)|(p-q)),所以 (gcd(p,q)le p-q),所以 (p+qle |S|+p-q),所以 (qle |S|-q),所以 (gcd(p,q)) 是长度为 (q) 的前缀的循环节,又因为 (gcd(p,q)|q) 所以循环节是整的,且 (gcd(p,q)) 是长度为 (|S|-q) 的后缀的循环节,所以 (gcd(p,q)) 是原串的循环节,Q.E.D.
计算概率公式
考虑另一种情况,当 (p+q>n+gcd(p,q)) 时,证明连 ((x,x+p)) 和 ((x,x+q)) 这些边之后无环。
首先连上 ((x,x+p)) 并对连通块缩点,形成(mod p) 的同余类,然后连上 ((x,(x+q)mod p)),形成 (gcd(p,q)) 个环,这些环必定会经过 ((p-gcd(p,q),p]) 中的至少一个点,如果其不能向后连边则此环不完整,所以无环。
得到连通块个数即为点数-边数,即方案数为 (k^{p+q-n})。
于是这题就只剩下数论推柿子部分了(!
把答案表示成一个 (k) 的多项式的形式,其他两项都很好算,暴力即可,时间复杂度 (O(nlog n))。
#include<bits/stdc++.h>
#define PB emplace_back
using namespace std;
typedef long long LL;
const int N = 100003, mod = 1e9 + 7;
int ksm(int a, int b){
int res = 1;
for(;b;b >>= 1, a = (LL)a * a % mod)
if(b & 1) res = (LL)res * a % mod;
return res;
}
void qmo(int &x){x += x >> 31 & mod;}
int n, k, a[N<<1], b[N<<1], pw[N], mu[N], pri[N], tot, ans;
bool notp[N]; vector<int> vec[N];
int main(){
scanf("%d%d", &n, &k);
notp[0] = notp[1] = true; mu[1] = pw[0] = 1;
for(int i = 1;i <= n;++ i) pw[i] = (LL)pw[i-1] * k % mod;
for(int i = n;i <= (n-1<<1);++ i) a[i] = (n<<1) - i - 1;
for(int i = 2;i <= n;++ i){
if(!notp[i]){pri[tot++] = i; mu[i] = mod - 1;}
for(int j = 0;j < tot && i * pri[j] <= n;++ j){
notp[i * pri[j]] = true;
if(i % pri[j]) mu[i * pri[j]] = mod - mu[i];
else break;
}
} for(int i = 1;i <= n;++ i)
for(int j = i;j <= n;j += i) vec[j].PB(i);
for(int p = 1;p < n;++ p){
int l = (n-1<<1) / p; memset(b+1, 0, l+1<<2);
for(int d : vec[p]){
int m = (n + d - 1) / p;
qmo(b[m] += mu[p / d] - mod);
ans = (ans + (m * (m-1ll) >> 1) % mod * pw[d] % mod * mu[p / d]) % mod;
} for(int i = l-1;i;-- i) qmo(b[i] += b[i+1] - mod);
for(int i = 1;i <= l;++ i) qmo(a[i * p] -= b[i] * (i-1ll) % mod);
} for(int i = n;i <= (n-1<<1);++ i) ans = (ans + (LL)a[i] * pw[i-n]) % mod;
printf("%lld
", (LL)ans * ksm(k, mod-1-n) % mod);
}
*CF1242E Planar Perimeter
题目描述:给定 (f) 个正整数 (a_i),构造简单平面图,边权为 (1),有 (f) 个内部区域,每个内部区域的周长分别为 (a_i),且外围周长尽可能小。
数据范围:(a_ige 3,sum a_ile 3cdot 10^5)。
Gym102576
*A Bags of Candies
题目描述:求 (V=[1,n]capN,E={(i,j)mid gcd(i,j)>1}) 的最大匹配。
数据范围:(nle 10^{11})。
solution
这好数竞啊(
首先 (1) 和 (>frac n2) 的质数必定无法配对,然后其他的必定可以匹配到至多只剩一个点。
设 (f(x)) 表示 (x) 的最大质因子,把每个点按 (f(x)) 分组,每一组两两可以匹配。最后会剩下一个,我们剩下 (2cdot f(x)) 就可以保证最后的还能继续匹配。
答案即为 (Biglfloordfrac{n-1-pi(n)+pi(frac n2)}{2}Big floor),用 min_25 筛算算即可。
*B Binomial
题目描述:给定 (n) 个正整数 (a_i),求 (sum_{i=1}^nsum_{j=1}^n(inom{a_i}{a_j}mod 2))。
数据范围:(n,a_ile 10^6)。
solution
众所周知的 Lucas 定理,枚举 (a_i),用 FMT 算即可。
-C Bookface
题目描述:给定 (n) 个自然数 (c_i) 和正整数 (d),每次操作可以将 (c_i) 加 (1) 或减 (1)(但 (0) 不能减),使得 (forall 1le i<jle n,|c_i-c_j|ge d)。(T) 组数据。
数据范围:(Tle 10^5,nle 2cdot 10^5,sum nle 10^6,c_ile3cdot 10^{11})。
-D Clique
题目描述:给定长为 (10^6) 的环上 (n) 个区间 ([l_i,r_i]),求“区间图”的最大环大小。多组数据。
数据范围:(nle 3000,sum nle 24000, ext{TL}=25 ext s)。
K To argue, or not to argue
题目描述:给定 (n imes m) 的网格图,去掉若干个点,求分配 (k) 对有区别的位置的方案数(mod(10^9+7)),使得每一对位置不相邻。(T) 组数据。
数据范围:(Tle 10,2kle nmle 144, ext{TL}=10 ext s)。
solution
二项式反演,设 (f_k) 表示钦定 (k) 对位置相邻的方案数,共有 (a) 个可选的位置,则
(f_k) 可以用轮廓线 dp 求出,时间复杂度 (O(nmk2^{min(n,m)}))。
#include<bits/stdc++.h>
#define PB emplace_back
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 144, M = 12, K = N>>1, mod = 1e9 + 7;
int ksm(int a, int b){
int res = 1;
for(;b;b >>= 1, a = (LL)a * a % mod)
if(b & 1) res = (LL)res * a % mod;
return res;
}
void qmo(int &x){x += x >> 31 & mod;}
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int T, n, m, k, lim, tot, fac[N+1], inv[N+1], dp[2][K][1<<M];
bool a[N][M];
void solve(){
read(n); read(m); read(k); tot = 0;
for(int i = 0;i < n;++ i)
for(int j = 0, ch;j < m;++ j){
do ch = getchar(); while(ch != '.' && ch != 'X');
tot += ((n < m ? a[j][i] : a[i][j]) = (ch == '.'));
}
if(tot < (k<<1)){puts("0"); return;}
if(n < m) swap(n, m); lim = 1<<m;
memset(dp[0], 0, sizeof dp);
int cur = 0, ans = 0; dp[0][0][0] = 1;
for(int i = 0;i < n;++ i)
for(int j = 0;j < m;++ j, cur ^= 1){
memset(dp[!cur], 0, sizeof dp[!cur]);
for(int x = 0;x <= k;++ x)
for(int S = 0;S < lim;++ S){
int &tmp = dp[!cur][x][S];
qmo(tmp += dp[cur][x][S & ~(1<<j)] - mod);
if(x){
if(i && a[i][j] && a[i-1][j] && !(S>>j&1))
qmo(tmp += dp[cur][x-1][S|(1<<j)] - mod);
if(j && a[i][j] && a[i][j-1] && !(S>>(j-1)&3))
qmo(tmp += dp[cur][x-1][S|(1<<j-1)] - mod);
}
}
}
for(int i = 0, pw = 1;i <= k;++ i, pw = pw * (mod-2ll) % mod)
ans = (ans + (LL)pw * fac[tot-2*i] % mod * inv[k-i] % mod * dp[cur][i][0]) % mod;
printf("%lld
", (LL)ans * fac[k] % mod * inv[tot-2*k] % mod);
}
int main(){
read(T); fac[0] = 1;
for(int i = 1;i <= N;++ i) fac[i] = (LL)fac[i-1] * i % mod;
inv[N] = ksm(fac[N], mod-2);
for(int i = N;i;-- i) inv[i-1] = (LL)inv[i] * i % mod;
while(T --) solve();
}
Gym102586
*C Sum Modulo
题目描述:给定 (n) 个正整数 (a_i) 和正整数 (m,k),对于初始为 (k) 的自然数 (X),每次操作以 (frac{a_i}{sum a_i}) 的概率生成 (i) 并将 (X) 变为 ((X-i)mod m),求将 (X) 变为 (0) 的期望步数(mod 998244353)。
数据范围:(nlemin(500,m-1),mle 10^{18},k<m,a_ile 100)。
solution
设 (f_k) 表示答案,(f_0=0)。用主元法解方程,最后是一个线性递推,时间复杂度 (O(n^3+n^2log m))。
-G Matrix Inversion
题目描述:给定自然数 (n,x,y),构造 (n imes n) 的矩阵 (M),其中 (1,2,dots,n^2) 各出现一次,且 (A_{(i-1)n+j}=M_{i,j}) 的序列 (A) 的逆序对数为 (x),(B_{(i-1)n+j}=M_{j,i}) 的序列 (B) 的逆序对数为 (y)。需判断无解。
数据范围:(nle 300,x,yleinom{n^2}2)。
*UOJ308 新年拯救计划
题目描述:给定 (n) 个点 (m) 条边的无向图,求 (k)-染色数(mod 6)。(T) 组数据。
数据范围:(Tle 5,nle 10^5,mle 2cdot 10^5,kle 10^4,) 无自环。
solution
众所周知,色多项式是整系数多项式,而 (forall nin,F(x)in[x],pinN_+[F(n)equiv F(nmod p)pmod p]),所以只用求 ((kmod 2))-染色数(mod 2) 和 ((kmod 3))-染色数(mod 3),然后再 CRT 合并即可。
这显然有手就行,时间复杂度 (O(n+m))。