4.21~4.27做题情况

udp:T3莫名爆零,T2被卡常,220->170滚粗

多项式真的好恶心啊,这周几乎就是在写各种模板而且大部分都是黑题

周六打了NOIOL2,T2线段树被卡常了,估分大概190-220吧

多项式

多项式乘法逆模板

多项式求逆,推式子+NTT

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 4e5 + 50,g = 3,mod = 998244353;
int n,N,l,rev[maxn],f[maxn],t[maxn],ans[maxn];
int read(){
   int x = 0;
   char c = getchar();
   while(c < '0' || c > '9') c = getchar();
   while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
   return x;
}
int qpow(int x,int k){
    long long d = 1,t = x;
    while(k){
        if(k & 1) d = d * t % mod;
        t = t * t % mod,k >>= 1;
    }
    return d;
}
void DNT(int *f,int op){
    for(int i = 0; i < N; i ++) if(i < rev[i]) swap(f[i],f[rev[i]]);
    for(int i = 1; i < N; i <<= 1){
        int w1 = qpow(g,(mod - 1) / (2 * i));
        for(int j = 0; j < N; j += 2 * i){
            int w = 1;
            for(int k = j; k < j + i; k ++){
                int t1 = f[k],t2 = 1ll * w * f[k + i] % mod;
                f[k] = (t1 + t2) % mod,f[k + i] = (t1 - t2 + mod) % mod;
                w = 1ll * w * w1 % mod;
            }
        }
    }
    if(!op){
        int inv = qpow(N,mod - 2);
        for(int i = 0; i < N; i ++) f[i] = 1ll * f[i] * inv % mod;
        for(int i = 1; i <= N / 2; i ++) swap(f[i],f[N - i]);//实现略奇葩,常数有点大
    }
}
void NTT(int n,int *f,int *g){
    N = 1,l = 0;
    while(N < 2 * n - 1) N <<= 1,l ++;
    for(int i = 1; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    DNT(f,1),DNT(g,1);
    for(int i = 0; i < N; i ++) f[i] = 1ll * (2 - 1ll * g[i] * f[i] % mod + mod) % mod * f[i] % mod;
    DNT(f,0);
}
void inv(int n,int * g){
    if(n == 1){
        g[0] = qpow(f[0],mod - 2);
        return;
    }
    inv((n + 1) / 2,g);
    for(int i = 0; i < n; i ++) t[i] = f[i];
    NTT(n,g,t);
    for(int i = n; i < N; i ++) g[i] = 0;
}
int main(){
    n = read();
    for(int i = 0; i < n; i ++) f[i] = read();
    inv(n,ans);
    for(int i = 0; i < n; i ++) printf("%d ",ans[i]);
    return 0;
}
任模多项式求逆模板

MTT模板题,也可以写三模NTT,不过比较麻烦 好像MTT也没简单到哪里去

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 3e5 + 50,mod = 1e9 + 7,P = 32768;
const double Pi = acos(-1);
int n,rev[maxn],f[maxn],inv[maxn],t[maxn];
struct cp{
    long double x,y;
    cp operator + (cp a){
        return {x + a.x,y + a.y};
    }
    cp operator - (cp a){
        return {x - a.x,y - a.y};
    }
    cp operator * (cp a){
        return {x * a.x - y * a.y,x * a.y + y * a.x};
    }
}p[maxn],q[maxn],a[maxn],b[maxn],w[maxn];
int read(){
   int x = 0;
   char c = getchar();
   while(c < '0' || c > '9') c = getchar();
   while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
   return x;
}
int qpow(int x,int k){
    long long d = 1,t = x;
    while(k){
        if(k & 1) d = d * t % mod;
        t = t * t % mod,k >>= 1;
    }
    return d;
}
void FFT(cp *a,int n,int op){
    for(int i = 0; i < n; i ++) if(i < rev[i]) swap(a[i],a[rev[i]]);
    for(int i = 1; i < n; i <<= 1){
        for(int j = 0; j < n; j += i << 1){
            for(int k = j; k < j + i; k ++){
                cp W = {w[n / i * (k - j)].x,op * w[n / i * (k - j)].y};
                cp t1 = a[k],t2 = W * a[k + i];
                a[k] = t1 + t2,a[k + i] = t1 - t2;
            }
        }
    }
    if(op == -1) for(int i = 0; i < n; i ++) a[i].x /= n,a[i].y /= n;
}
void MTT(int *f,int *g,int *h,int n){
    int N = 1,l = 0;
    while(N < 2 * n - 1) N <<= 1,l ++;
    for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    for(int i = 1; i < N; i <<= 1)
        for(int j = 0; j < i; j ++)
            w[N / i * j] = {cos(j * Pi / i),sin(j * Pi / i)};
    for(int i = 0; i < n; i ++) p[i] = {f[i] % P,f[i] / P},q[i] = {g[i] % P,g[i] / P};
    for(int i = n; i < N; i ++) p[i] = q[i] = {0,0};
    FFT(p,N,1),FFT(q,N,1);
    for(int i = 0; i < N; i ++){
        int t = (N - i) % N;
        a[i] = (cp){(p[i].x + p[t].x) / 2,(p[i].y - p[t].y) / 2} * q[i];
        b[i] = (cp){(p[i].y + p[t].y) / 2,(p[t].x - p[i].x) / 2} * q[i];
    }
    FFT(a,N,-1),FFT(b,N,-1);
    for(int i = 0; i < n; i ++){
        long long x1 = a[i].x + 0.5,x2 = a[i].y + 0.5,x3 = b[i].x + 0.5,x4 = b[i].y + 0.5;
        x1 %= mod,x2 %= mod,x3 %= mod,x4 %= mod;
        h[i] = (((x4 * P % mod * P % mod + x2 * P % mod) % mod + x3 * P % mod) % mod + x1) % mod;
    }
}
void solve(int n,int *inv){
    if(n == 1){
        inv[0] = qpow(f[0],mod - 2);
        return;
    }
    solve((n + 1) / 2,inv);
    MTT(f,inv,t,n),MTT(t,inv,t,n);
    for(int i = 0; i < n; i ++) inv[i] = (2 * inv[i] % mod - t[i] + mod) % mod;
}
int main(){
    n = read();
    for(int i = 0; i < n; i ++) f[i] = read();
    solve(n,inv);
    for(int i = 0; i < n; i ++) printf("%d ",inv[i]);
    return 0;
}
多项式求ln模板

两边求导就可以把ln化掉,乘起来后再求个积分就可以了

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 3e5 + 50,g = 3,mod = 998244353;
int n,rev[maxn],F[maxn],Inv[maxn],Dev[maxn],Ln[maxn],T[maxn];
int read(){
    int x = 0;
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
    return x;
}
int qpow(int x,int k){
    long long d = 1,t = x;
    while(k){
        if(k & 1) d = d * t % mod;
        t = t * t % mod,k >>= 1;
    }
    return d;
}
void NTT(int *F,int n,int op){
    for(int i = 0; i < n; i ++) if(i < rev[i]) swap(F[i],F[rev[i]]);
    for(int i = 1; i < n; i <<= 1){
        int w1 = qpow(g,(mod - 1) / (2 * i));
        for(int j = 0; j < n; j += 2 * i){
            int w = 1;
            for(int k = j; k < j + i; k ++){
                int t1 = F[k],t2 = 1ll * F[k + i] * w % mod;
                F[k] = (t1 + t2) % mod,F[k + i] = (t1 - t2 + mod) % mod;
                w = 1ll * w * w1 % mod;
            }
        }
    }
    if(!op){
        int inv = qpow(n,mod - 2);
        for(int i = 0; i < n; i ++) F[i] = 1ll * F[i] * inv % mod;
        for(int i = 1; i <= n / 2; i ++) swap(F[i],F[n - i]);
    }
}
void get_Inv(int *F,int *G,int n){
    if(n == 1){
        G[0] = qpow(F[0],mod - 2);
        return;
    }
    get_Inv(F,G,(n + 1) / 2);
    int N = 1,l = 0;
    while(N < 2 * n - 1) N <<= 1,l ++;
    for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    for(int i = 0; i < n; i ++) T[i] = F[i];
    NTT(T,N,1),NTT(G,N,1);
    for(int i = 0; i < N; i ++) G[i] = (2ll * G[i] % mod - 1ll * T[i] * G[i] % mod * G[i] % mod + mod) % mod;
    NTT(G,N,0);
    for(int i = n; i < N; i ++) G[i] = 0;
}
void get_Dev(int *F,int *G,int n){
    for(int i = 0; i < n; i ++) G[i] = 1ll * (i + 1) * F[i + 1] % mod;
}
void get_Int(int *F,int *G,int n){
    for(int i = n - 1; i >= 1; i --) G[i] = 1ll * F[i - 1] * qpow(i,mod - 2) % mod;
    G[0] = 0;
}
void get_ln(int *F,int *G,int n){
    get_Dev(F,Dev,n);
    get_Inv(F,Inv,n);
    int N = 1,l = 0;
    while(N < 2 * n - 1) N <<= 1,l ++;
    for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
    NTT(Dev,N,1),NTT(Inv,N,1);
    for(int i = 0; i < N; i ++) G[i] = 1ll * Dev[i] * Inv[i] % mod;
    NTT(G,N,0);
    get_Int(G,G,n);
}
int main(){
    n = read();
    for(int i = 0; i < n; i ++) F[i] = read();
    get_ln(F,Ln,n);
    for(int i = 0; i < n; i ++) printf("%d ",Ln[i]);
    return 0;
}
多项式求exp模板

类似于求逆的思想,先两边取ln、移项,再套牛顿迭代即可

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 3e5 + 50,mod = 998244353,g = 3;
int n,rev[maxn],F[maxn],G[maxn],H[maxn],T[maxn];
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
int qpow(int x,int k){
	long long d = 1,t = x;
	while(k){
		if(k & 1) d = d * t % mod;
		t = t * t % mod,k >>= 1;
	}
	return d;
}
void NTT(int *F,int n,int p){
	for(int i = 0; i < n; i ++) if(i < rev[i]) swap(F[i],F[rev[i]]);
	for(int i = 1; i < n; i <<= 1){
		int w1 = qpow(g,(mod - 1) / (i << 1));
		for(int j = 0; j < n; j += (i << 1)){
			int w = 1;
			for(int k = j; k < j + i; k ++){
				int t1 = F[k],t2 = 1ll * w * F[k + i] % mod;
				F[k] = (t1 + t2) % mod,F[k + i] = (t1 - t2 + mod) % mod;
				w = 1ll * w * w1 % mod;
			}
		}
	}
	if(!p){
		int inv = qpow(n,mod - 2);
		for(int i = 0; i < n; i ++) F[i] = 1ll * F[i] * inv % mod;
		for(int i = 1; i <= (n >> 1); i ++) swap(F[i],F[n - i]);
	}
}
void get_Dev(int *F,int *G,int n){
	for(int i = 0; i < n; i ++) G[i] = 1ll * F[i + 1] * (i + 1) % mod;
	G[n - 1] = 0;
}
void get_Int(int *F,int *G,int n){
	for(int i = n; i >= 1; i --) G[i] = 1ll * F[i - 1] * qpow(i,mod - 2) % mod;
	G[0] = 0;
}
void get_Inv(int *F,int *G,int n){
	if(n == 1){
		G[0] = qpow(F[0],mod - 2);
		return;
	}
	get_Inv(F,G,(n + 1) >> 1);
	int N = 1,l = 0;
	while(N < 2 * n - 1) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	for(int i = 0; i < n; i ++) T[i] = F[i];
	NTT(T,N,1),NTT(G,N,1);
	for(int i = 0; i < N; i ++) G[i] = 1ll * (2 - 1ll * T[i] * G[i] % mod + mod) % mod * G[i] % mod;
	NTT(G,N,0);
	for(int i = n; i < N; i ++) G[i] = 0;
	for(int i = 0; i < N; i ++) T[i] = 0;
}
void get_Ln(int *F,int *G,int n){
	int N = 1,l = 0;
	while(N < 2 * n - 1) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	get_Inv(F,G,n);
	get_Dev(F,T,n);
	NTT(T,N,1),NTT(G,N,1);
	for(int i = 0; i < N; i ++) G[i] = 1ll * T[i] * G[i] % mod;
	NTT(G,N,0);
	get_Int(G,G,n - 1);
	for(int i = n; i < N; i ++) G[i] = 0;
	for(int i = 0; i < N; i ++) T[i] = 0;
}
void get_Exp(int *F,int *G,int n){
	if(n == 1){
		G[0] = 1;
		return;
	}
	get_Exp(F,G,(n + 1) >> 1);
	get_Ln(G,H,n);
	int N = 1,l = 0;
	while(N < 2 * n + 1) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	for(int i = 0; i < n; i ++) H[i] = (F[i] - H[i] + mod) % mod;
	H[0] = (H[0] + 1) % mod;
	NTT(G,N,1),NTT(H,N,1);
	for(int i = 0; i < N; i ++) G[i] = 1ll * G[i] * H[i] % mod;
	NTT(G,N,0);
	for(int i = n; i < N; i ++) G[i] = 0;
	for(int i = 0; i < N; i ++) H[i] = 0;
}
int main(){
	n = read();
	for(int i = 0; i < n; i ++) F[i] = read();
	get_Exp(F,G,n);
	for(int i = 0; i < n; i ++) printf("%d ",G[i]);
	return 0;
}
多项式开根模板

也是用求逆的思想,推出式子写就好了

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 3e5 + 50,mod = 998244353,g = 3,inv2 = 499122177;
int n,rev[maxn],F[maxn],G[maxn],H[maxn],T[maxn];
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
int qpow(int x,int k){
	long long d = 1,t = x;
	while(k){
		if(k & 1) d = d * t % mod;
		t = t * t % mod,k >>= 1;
	}
	return d;
}
void NTT(int *F,int n,int p){
	for(int i = 0; i < n; i ++) if(i < rev[i]) swap(F[i],F[rev[i]]);
	for(int i = 1; i < n; i *= 2){
		int w1 = qpow(g,(mod - 1) / (2 * i));
		for(int j = 0; j < n; j += 2 * i){
			int w = 1;
			for(int k = j; k < j + i; k ++){
				int t1 = F[k],t2 = 1ll * F[k + i] * w % mod;
				F[k] = (t1 + t2) % mod,F[k + i] = (t1 - t2 + mod) % mod;
				w = 1ll * w * w1 % mod;
			}
		}
	}
	if(!p){
		int inv = qpow(n,mod - 2);
		for(int i = 0; i < n; i ++) F[i] = 1ll * F[i] * inv % mod;
		for(int i = 1; i <= n / 2; i ++) swap(F[i],F[n - i]);
	}
}
void get_Inv(int *F,int *G,int n){
	if(n == 1){
		G[0] = qpow(F[0],mod - 2);
		return;
	}
	get_Inv(F,G,(n + 1) / 2);
	int N = 1,l = 0;
	while(N < 2 * n - 1) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	for(int i = 0; i < n; i ++) T[i] = F[i];
	for(int i = n; i < N; i ++) T[i] = 0;
	NTT(T,N,1),NTT(G,N,1);
	for(int i = 0; i < N; i ++) G[i] = 1ll * (2 - 1ll * T[i] * G[i] % mod + mod) % mod * G[i] % mod;
	NTT(G,N,0);
	for(int i = n; i < N; i ++) G[i] = 0;
}
void get_Sqrt(int *F,int *G,int n){
	if(n == 1){
		G[0] = 1;
		return;
	}
	get_Sqrt(F,G,(n + 1) / 2);
	get_Inv(G,H,n);
	int N = 1,l = 0;
	while(N < 2 * n - 1) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	for(int i = 0; i < n; i ++) T[i] = F[i];
	for(int i = n; i < N; i ++) T[i] = 0;
	NTT(T,N,1),NTT(H,N,1);
	for(int i = 0; i < N; i ++) H[i] = 1ll * T[i] * H[i] % mod;
	NTT(H,N,0);
	for(int i = 0; i < n; i ++) G[i] = 1ll * (G[i] + H[i]) % mod * inv2 % mod;
	for(int i = n; i < N; i ++) G[i] = 0;
	for(int i = 0; i < N; i ++) H[i] = 0;
}
int main(){
	n = read();
	for(int i = 0; i < n; i ++) F[i] = read();
	get_Sqrt(F,G,n);
	for(int i = 0; i < n; i ++) printf("%d ",G[i]);
	return 0;
}
多项式开根加强版

跟模板的区别是只保证 a 0 a_0 a0为模 998244353 998244353 998244353的二次剩余,即边界时要自行求出 b 0 b_0 b0使 b 0 2 ≡ a 0 ( m o d 998244353 ) b_0^2 \equiv a_0 \pmod{998244353} b02a0(mod998244353),可以用Cipolla算法或由原根的次幂遍历模数的完系用BSGS解出。虽然BSGS较慢但实现简单,所以这里用的是BSGSBSGS模板在下面)

#include <iostream>
#include <cstdio>
#include <map>
#include <cmath>
using namespace std;
const int maxn = 3e5 + 50,mod = 998244353,g = 3,inv2 = 499122177;
int n,rev[maxn],F[maxn],G[maxn],H[maxn],T[maxn];
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
int qpow(int x,int k){
	long long d = 1,t = x;
	while(k){
		if(k & 1) d = d * t % mod;
		t = t * t % mod,k >>= 1;
	}
	return d;
}
int BSGS(int a,int k){
	map <int,int> mp;
	int len = ceil(sqrt(mod)),pw = 1;
	long long d = 1;
	for(int i = 1; i <= len; i ++) d = d * a % mod,mp[1ll * d * k % mod] = i;
	for(int i = 1; i <= len; i ++){
		pw = pw * d % mod;
		if(mp[pw]) return i * len - mp[pw];
	}
	return -1;
}
void NTT(int *F,int n,int p){
	for(int i = 0; i < n; i ++) if(i < rev[i]) swap(F[i],F[rev[i]]);
	for(int i = 1; i < n; i <<= 1){
		int w1 = qpow(g,(mod - 1) / (i << 1));
		for(int j = 0; j < n; j += i << 1){
			int w = 1;
			for(int k = j; k < j + i; k ++){
				int t1 = F[k],t2 = 1ll * w * F[k + i] % mod;
				F[k] = (t1 + t2) % mod,F[k + i] = (t1 - t2 + mod) % mod;
				w = 1ll * w * w1 % mod;
			}
		}
	}
	if(!p){
		int inv = qpow(n,mod - 2);
		for(int i = 0; i < n; i ++) F[i] = 1ll * F[i] * inv % mod;
		for(int i = 1; i <= (n >> 1); i ++) swap(F[i],F[n - i]);
	}
}
void get_Inv(int *F,int *G,int n){
	if(n == 1){
		G[0] = qpow(F[0],mod - 2);
		return;
	}
	get_Inv(F,G,(n + 1) / 2);
	int N = 1,l = 0;
	while(N < 2 * n - 1) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	for(int i = 0; i < n; i ++) T[i] = F[i];
	for(int i = n; i < N; i ++) T[i] = 0;
	NTT(T,N,1),NTT(G,N,1);
	for(int i = 0; i < N; i ++) G[i] = 1ll * (2 - 1ll * G[i] * T[i] % mod + mod) % mod * G[i] % mod;
	NTT(G,N,0);
	for(int i = n; i < N; i ++) G[i] = 0;
}
void get_Sqrt(int *F,int *G,int n){
	if(n == 1){
		G[0] = qpow(3,BSGS(3,F[0]) / 2);
		return;
	}
	get_Sqrt(F,G,(n + 1) / 2);
	get_Inv(G,H,n);
	int N = 1,l = 0;
	while(N < 2 * n - 1) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	for(int i = 0; i < n; i ++) T[i] = F[i];
	for(int i = n; i < N; i ++) T[i] = 0;
	NTT(T,N,1),NTT(H,N,1);
	for(int i = 0; i < N; i ++) T[i] = 1ll * T[i] * H[i] % mod;
	NTT(T,N,0);
	for(int i = 0; i < n; i ++) G[i] = 1ll * (T[i] + G[i]) % mod * inv2 % mod;
	for(int i = 0; i < N; i ++) H[i] = 0;
}
int main(){
	n = read();
	for(int i = 0; i < n; i ++) F[i] = read();
	get_Sqrt(F,G,n);
	for(int i = 0; i < n; i ++) printf("%d ",G[i]);
	return 0;
}
CF755G PolandBall and Many Other Balls

大概算倍增FFT的模板题?

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1 << 16,mod = 998244353,g = 3;
int n,m,N = 1,l,rev[maxn],t1[maxn],t2[maxn],s[3][maxn],f[3][maxn];
int qpow(int x,int k){
	long long d = 1,t = x;
	while(k){
		if(k & 1) d = d * t % mod;
		t = t * t % mod,k >>= 1;
	}
	return d;
}
void DNT(int *F,int p){
	for(int i = 0; i < N; i ++) if(i < rev[i]) swap(F[i],F[rev[i]]);
	for(int i = 1; i < N; i <<= 1){
		int w1 = qpow(g,(mod - 1) / (i << 1));
		for(int j = 0; j < N; j += i << 1){
			int w = 1;
			for(int k = j; k < j + i; k ++){
				int t1 = F[k],t2 = 1ll * w * F[k + i] % mod;
				F[k] = (t1 + t2) % mod,F[k + i] = (t1 - t2 + mod) % mod;
				w = 1ll * w * w1 % mod;
			}
		}
	}
	if(!p){
		int inv = qpow(N,mod - 2);
		for(int i = 0; i < N; i ++) F[i] = 1ll * F[i] * inv % mod;
		for(int i = 1; i <= (N >> 1); i ++) swap(F[i],F[N - i]);
	}
}
void NTT(int *F,int *G,int *H){
	for(int i = 0; i <= m; i ++) t1[i] = F[i],t2[i] = G[i];
	for(int i = m + 1; i < N; i ++) t1[i] = t2[i] = 0;
	DNT(t1,1),DNT(t2,1);
	for(int i = 0; i < N; i ++) t1[i] = 1ll * t1[i] * t2[i] % mod;
	DNT(t1,0);
	for(int i = 0; i <= m; i ++) H[i] = (H[i] + t1[i]) % mod;
}
void Mul(int x,int a,int b){
	for(int i = 0; i <= m; i ++) s[x][i] = 0;
	NTT(f[a],f[b],s[x]);
	NTT(f[a - 1],f[b - 1],s[x] + 1);
	s[x][m + 1] = 0;
}
void Add(){
	for(int i = 0; i <= m; i ++){
		f[0][i] = f[1][i],f[1][i] = f[2][i];
		f[2][i] = (f[1][i] + (i ? (f[1][i - 1] + f[0][i - 1]) % mod : 0)) % mod;
	}
}
int main(){
	f[2][0] = 1;
	scanf("%d%d",&n,&m);
	while(N < ((m + 1) << 1)) N <<= 1,l ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
	int p = 30;
	while((n & (1 << p)) == 0) p --;
	for(int i = p; i >= 0; i --){
		if(n & (1 << i)) Add();
		if(i){
			Mul(2,2,2),Mul(1,2,1),Mul(0,1,1);
			for(int j = 0; j <= m; j ++) f[0][j] = s[0][j],f[1][j] = s[1][j],f[2][j] = s[2][j];
		}
	}
	for(int i = 1; i <= m; i ++) printf("%d ",f[2][i]);
	return 0;
}
分治FFT模板

其实这题可以直接推式子求逆做,复杂度还少一个 log ⁡ \log log,但毕竟是来学分治的所以还是老老实实打分治吧

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 3e5 + 50,mod = 998244353,g = 3;
int n,rev[maxn],F[maxn],G[maxn],t1[maxn],t2[maxn];
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
int qpow(int x,int k){
	long long d = 1,t = x;
	while(k){
		if(k & 1) d = d * t % mod;
		t = t * t % mod,k >>= 1;
	}
	return d;
}
void NTT(int *F,int n,int p){
	for(int i = 0; i < n; i ++) if(i < rev[i]) swap(F[i],F[rev[i]]);
	for(int i = 1; i < n; i <<= 1){
		int w1 = qpow(g,(mod - 1) / (i << 1));
		for(int j = 0; j < n; j += (i << 1)){
			int w = 1;
			for(int k = j; k < j + i; k ++){
				int t1 = F[k],t2 = 1ll * w * F[k + i] % mod;
				F[k] = (t1 + t2) % mod,F[k + i] = (t1 - t2 + mod) % mod;
				w = 1ll * w * w1 % mod;
			}
		}
	}
	if(!p){
		int inv = qpow(n,mod - 2);
		for(int i = 0; i < n; i ++) F[i] = 1ll * F[i] * inv % mod;
		for(int i = 1; i <= n / 2; i ++) swap(F[i],F[n - i]);
	}
}
void solve(int l,int r){
	// cout << l << ' ' << r << endl;
	if(l == r) return;
	int mid = (l + r) / 2;
	solve(l,mid);
	int N = 1,lg = 0;
	while(N < ((r - l + 1) << 1)) N <<= 1,lg ++;
	for(int i = 0; i < N; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
	for(int i = 0; i <= mid - l; i ++) t1[i] = G[l + i];
	for(int i = mid - l + 1; i < N; i ++) t1[i] = 0;
	for(int i = 0; i <= r - l; i ++) t2[i] = F[i];
	for(int i = r - l + 1; i < N; i ++) t2[i] = 0;
	NTT(t1,N,1),NTT(t2,N,1);
	for(int i = 0; i < N; i ++) t1[i] = 1ll * t1[i] * t2[i] % mod;
	NTT(t1,N,0);
	for(int i = mid - l + 1; i <= r - l; i ++) G[l + i] = (G[l + i] + t1[i]) % mod;
	solve(mid + 1,r);
}
int main(){
	n = read(),G[0] = 1;
	for(int i = 1; i < n; i ++) F[i] = read();
	solve(0,n - 1);
	for(int i = 0; i < n; i ++) printf("%d ",G[i]);
	return 0;
}
[TJOI2007] 可爱的质数

BSGS模板,为了做开根加强版特意来学的,没写hash,用了STL的map,复杂度多了一个 log ⁡ \log log,但这题关系不大
原来世界上还有这么短的代码就可以A掉的题

#include <iostream>
#include <map>
#include <cmath>
using namespace std;
int a,k,p,len;
long long d = 1;
map <int,int> mp;
int main(){
	cin >> p >> a >> k;
	len = ceil(sqrt(p));
	for(int i = 1; i <= len; i ++) d = d * a % p,mp[d * k % p] = i;
	long long pw = d;
	for(int i = 1; i <= len; i ++){
		if(mp[pw]){
			cout << i * len - mp[pw] << endl;
			return 0;
		}
		pw = pw * d % p;
	}
	cout << "no solution" << endl;
	return 0;
}

NOIOL2

涂色游戏

一个sb题,我居然想了快1.5h,太菜了。

不妨设 p 1 < p 2 p_1 < p_2 p1<p2,易知可以贪心的将每个 p 2 p_2 p2的倍数染成蓝色。则原题显然可以转化为每两个相邻的 p 2 p_2 p2的倍数所组成的开区间中 p 1 p_1 p1的倍数个数的最大值是否大于等于 k k k。以下考虑计算这个最大值。

考虑每两个相邻的 p 2 p_2 p2的倍数 l , r l,r l,r。设第一个大于 l l l p 1 p_1 p1倍数为 l + x l + x l+x,则 ( l , r ) (l,r) (l,r) p 1 p_1 p1倍数的个数为 ⌊ r − ( l + x ) p 1 ⌋ + 1 = ⌊ p 2 − x p 1 ⌋ + 1 \Big\lfloor\frac{r - (l + x)}{p_1}\Big\rfloor + 1 = \Big\lfloor\frac{p_2 - x}{p_1}\Big\rfloor + 1 p1r(l+x)+1=p1p2x+1。一方面,我们希望这个值尽量大,所以我们要使 x x x尽量小;另一方面, x x x存在的充要条件为关于 a , b a,b a,b的方程 a p 1 − b p 2 = x ap_1 - bp_2 = x ap1bp2=x有整数解,即 gcd ⁡ ( p 1 , p 2 )    ∣    x \gcd(p_1,p_2) \;\Big| \;x gcd(p1,p2)x,所以 x ⩾ gcd ⁡ ( p 1 , p 2 ) x \geqslant \gcd(p_1,p_2) xgcd(p1,p2) ;综合以上两个方面,可以得到使 p 1 p_1 p1倍数个数最大的 x x x就是 gcd ⁡ ( p 1 , p 2 ) \gcd(p_1,p_2) gcd(p1,p2) !!

又显然这个东西每 l c m ( p 1 , p 2 ) lcm(p_1,p_2) lcm(p1,p2)为一个循环节,而 l c m ( p 1 , p 2 ) < 1 0 18 < 1 0 20 lcm(p_1,p_2) < 10 ^ {18} < 10 ^ {20} lcm(p1,p2)<1018<1020,所以一定会出现所有情况。故我们只需要比较 ⌊ p 2 − gcd ⁡ ( p 1 , p 2 ) p 1 ⌋ + 1 \Big\lfloor\frac{p_2 - \gcd(p_1,p_2)}{p_1}\Big\rfloor + 1 p1p2gcd(p1,p2)+1 k k k的大小即可。

注意还要特判 k = 1 k = 1 k=1的情况。考完以后听说是原题,一看好多人抄原题代码不特判,心理瞬间平衡

把最后的式子移个项就变成代码中的式子了,这么写比较好查错

附上原题链接

#include <iostream>
#include <cstdio>
using namespace std;
int T,a,b,k;
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
int gcd(int x,int y){
	if(!y) return x;
	else return gcd(y,x % y);
}
int main(){
	// freopen("color.in","r",stdin);
	// freopen("color.out","w",stdout);
	T = read();
	while(T --){
		a = read(),b = read(),k = read();
		if(k == 1){
			printf("NO\n");
			continue;
		}
		int t = gcd(a,b);
		a /= t,b /= t;
		if(a > b) swap(a,b);
		if(1ll * (k - 1) * a + 1 < b) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}
子序列问题

题解……写不动了

考场上也做出来了,但线段树被卡常,于是 100 p t s − > 70 p t s 100pts -> 70pts 100pts>70pts,太菜了

CCF评测机是8700k,我是不是还有戏

pushdown判个tag != 0 luogu就95了…

修改过的AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 50,maxm = 4 * maxn,mod = 1e9 + 7;
int n,m,ans,lasts,a[maxn],t[maxn],last[maxn],s[maxm],tag[maxm];
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
void update(int L,int R,int k,int x,int l,int r){
	if(L <= l && R >= r){
		s[x] = (s[x] + 1ll * (r - l + 1) * k % mod) % mod,tag[x] = (tag[x] + k) % mod;
		return;
	}
	int mid = (l + r) / 2;
	if(tag[x]){
		s[x << 1] = (s[x << 1] + 1ll * (mid - l + 1) * tag[x] % mod) % mod,s[x << 1 | 1] = (s[x << 1 | 1] + 1ll * (r - mid) * tag[x] % mod) % mod;
		tag[x << 1] = (tag[x << 1] + tag[x]) % mod,tag[x << 1 | 1] = (tag[x << 1 | 1] + tag[x]) % mod;
		tag[x] = 0;
	}
	if(L <= mid) update(L,R,k,x << 1,l,mid);
	if(R > mid) update(L,R,k,x << 1 | 1,mid + 1,r);
	s[x] = (s[x << 1] + s[x << 1 | 1]) % mod;
}
int query(int L,int R,int x,int l,int r){
	if(L <= l && R >= r) return s[x];
	int mid = (l + r) / 2,sum = 0;
	if(tag[x]){
		s[x << 1] = (s[x << 1] + 1ll * (mid - l + 1) * tag[x] % mod) % mod,s[x << 1 | 1] = (s[x << 1 | 1] + 1ll * (r - mid) * tag[x] % mod) % mod;
		tag[x << 1] = (tag[x << 1] + tag[x]) % mod,tag[x << 1 | 1] = (tag[x << 1 | 1] + tag[x]) % mod;
		tag[x] = 0;
	}
	if(L <= mid) sum = query(L,R,x << 1,l,mid);
	if(R > mid) sum = (sum + query(L,R,x << 1 | 1,mid + 1,r)) % mod;
	s[x] = (s[x << 1] + s[x << 1 | 1]) % mod;
	return sum;
}
int main(){
	// freopen("sequence.in","r",stdin);
	// freopen("sequence.out","w",stdout);
	n = read();
	for(int i = 1; i <= n; i ++) a[i] = t[i] = read();
	sort(t + 1,t + n + 1);
	m = unique(t + 1,t + n + 1) - t - 1;
	for(int i = 1; i <= n; i ++) a[i] = lower_bound(t + 1,t + m + 1,a[i]) - t;
	for(int i = 1; i <= n; i ++){
		int tmp = (2 * query(last[a[i]] + 1,i,1,1,n) % mod + (i - last[a[i]])) % mod;
		ans = ((ans + lasts) % mod + tmp) % mod;
		update(last[a[i]] + 1,i,1,1,1,n);
		last[a[i]] = i,lasts = (lasts + tmp) % mod;
	}
	printf("%d\n",ans);
	return 0;
}
游戏

考场上只打了链的20分,还有20分暴力没打

正解是树形背包,不过我现在也不会证为啥能那么做,感觉网上我看到的解释都是错的。个人认为 g g g纯粹就是拿来反演的工具,没有实际意义

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 5050,mod = 998244353;
int n,m,x,y,cnt,a[maxn],frac[maxn],last[maxn],size[maxn],size1[maxn],g[maxn],f[maxn][maxn],C[maxn][maxn],t[maxn];
struct edge{
	int v,nxt;
}e[2 * maxn];
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
void insert(int x,int y){
	cnt ++,e[cnt].v = y,e[cnt].nxt = last[x],last[x] = cnt;
}
void dfs(int u,int fa){
	size[u] = 1,size1[u] = a[u],f[u][0] = 1;
	for(int i = last[u]; i; i = e[i].nxt){
		int v = e[i].v;
		if(v == fa) continue;
		dfs(v,u);
		for(int j = 0; j <= size[u] + size[v]; j ++) t[j] = 0;
		for(int j = 0; j <= min(size1[u],size[u] - size1[u]); j ++){
			if(!f[u][j]) continue;
			for(int k = 0; k <= min(size1[v],size[v] - size1[v]); k ++){
				if(!f[v][k]) continue;
				t[j + k] = (t[j + k] + 1ll * f[u][j] * f[v][k] % mod) % mod;
			}
		}
		size[u] += size[v],size1[u] += size1[v];
		for(int j = 0; j <= size[u]; j ++) f[u][j] = t[j];
	}
	for(int i = min(size1[u],size[u] - size1[u]); i >= 1; i --) f[u][i] = (f[u][i] + 1ll * f[u][i - 1] * ((a[u] ? size[u] - size1[u] : size1[u]) - i + 1) % mod) % mod;
}
int main(){
	// freopen("match.in","r",stdin);
	// freopen("match.out","w",stdout);
	n = read();
	m = n / 2,frac[0] = 1;
	for(int i = 0; i <= n; i ++){
		C[i][0] = 1;
		if(i) frac[i] = 1ll * frac[i - 1] * i % mod;;
		for(int j = 1; j <= i; j ++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
	}
	for(int i = 1; i <= n; i ++) a[i] = getchar() - '0';
	for(int i = 1; i < n; i ++){
		x = read(),y = read();
		insert(x,y),insert(y,x);
	}
	dfs(1,0);
	for(int i = 0; i <= m; i ++) g[i] = 1ll * f[1][i] * frac[m - i] % mod;
	for(int i = 0; i <= m; i ++){
		int s = 0;
		for(int j = i; j <= m; j ++){
			if((j - i) % 2 == 0) s = (s + 1ll * C[j][i] * g[j] % mod) % mod;
			else s = (s - 1ll * C[j][i] * g[j] % mod + mod) % mod;
		}
		printf("%d\n",s);
	}
	return 0;
}

其他杂题

教主的魔法

n \sqrt{n} n 的大小分块,涉及到整个区间的修改操作打tag,随时保证每块内有序,查询时二分一下即可,时间复杂度大概是 O ( Q n log ⁡ 2 n ) O(Q\sqrt{n}\log_2{\sqrt{n}}) O(Qn log2n )? 没仔细算。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 1e6 + 50,qmaxn = 1e3 + 50;
int n,m,l,r,k,len,a[maxn],d[maxn],tag[qmaxn];
char type;
int read(){
    int x = 0;
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
    return x;
}
inline int pos(int x){
    return (x - 1) / len + 1;
}
inline int lb(int x){
    return (x - 1) * len + 1;
}
inline int rb(int x){
    return min(n,x * len);
}
void update(int l,int r,int k){
    if(pos(l) == pos(r)){
        for(int i = l; i <= r; i ++) a[i] += k;
        for(int i = lb(pos(l)); i <= rb(pos(l)); i ++) d[i] = a[i];
        sort(d + lb(pos(l)),d + rb(pos(l)) + 1);
    }else{
        for(int i = l; i <= rb(pos(l)); i ++) a[i] += k;
        for(int i = lb(pos(l)); i <= rb(pos(l)); i ++) d[i] = a[i];
        sort(d + lb(pos(l)),d + rb(pos(l)) + 1);
        for(int i = lb(pos(r)); i <= r; i ++) a[i] += k;
        for(int i = lb(pos(r)); i <= rb(pos(r)); i ++) d[i] = a[i];
        sort(d + lb(pos(r)),d + rb(pos(r)) + 1);
        for(int i = pos(l) + 1; i <= pos(r) - 1; i ++) tag[i] += k;
    }
}
int query(int l,int r,int k){
    int s = 0;
    if(pos(l) == pos(r)){
        for(int i = l; i <= r; i ++) if(a[i] + tag[pos(i)] >= k) s ++;
        return s;
    }else{
        for(int i = l; i <= rb(pos(l)); i ++) if(a[i] + tag[pos(i)] >= k) s ++;
        for(int i = lb(pos(r)); i <= r; i ++) if(a[i] + tag[pos(i)] >= k) s ++;
        for(int i = pos(l) + 1; i <= pos(r) - 1; i ++){
            int t = lower_bound(d + lb(i),d + rb(i) + 1,k - tag[i]) - d;
            s += rb(i) - t + 1;
        }
        return s;
    }
}
int main(){
    n = read(),m = read(),len = sqrt(n);
    for(int i = 1; i <= n; i ++) a[i] = d[i] = read();
    for(int i = 1; i <= pos(n); i ++) sort(d + lb(i),d + rb(i) + 1);
    while(m --){
        do type = getchar();
        while(type != 'A' && type != 'M');
        l = read(),r = read(),k = read();
        if(type == 'M') update(l,r,k);
        else printf("%d\n",query(l,r,k));
    }
    return 0;
}

}
魔法指纹

一道……打表题,对,一道紫色打表题

我们先打一张表, S i S_i Si [ 1 , i ∗ 1 0 6 ] [1,i * 10 ^ 6] [1,i106]中的个数,则表中只需要存 1000 1000 1000个数,可以接受。而对于询问 [ A , B ] [A,B] [A,B],我们只需要计算 [ 1 , B ] [1,B] [1,B]中的个数减去 [ 1 , A − 1 ] [1,A - 1] [1,A1]中的个数即可,则问题转化为求一个区间 [ 1 , n ] [1,n] [1,n]的和。设 n = k ∗ 1 0 6 + b n = k * 10^6 + b n=k106+b(其中 0 ⩽ b < 1 0 6 0 \leqslant b < 10 ^ 6 0b<106),则小于等于 k ∗ 1 0 6 k * 10 ^ 6 k106的部分已经求出( S k S_k Sk),大于 k ∗ 1 0 6 k * 10 ^ 6 k106的部分直接暴力求即可

#include <iostream>
#include <cmath>
using namespace std;
int l,r,s[1050] = {0,2045,3089,3839,4196,4512,4828,5186,5935,6979,8453,9319,10363,10666,10886,11040,11155,11239,11364,11710,12637,13015,13573,14323,14544,14748,14902,15020,15154,15300,15682,15792,16062,16365,16722,16898,17102,17270,17398,17487,17562,17647,17773,18071,18292,18608,18784,19004,19172,19260,19329,19398,19486,19654,19874,20050,20366,20587,20885,21011,21096,21171,21260,21388,21556,21760,21936,22293,22596,22866,22977,23359,23504,23638,23756,23910,24114,24336,25085,25643,26021,26948,27295,27419,27503,27618,27772,27992,28295,29339,30205,32227,32981,33205,33276,33362,33477,33645,33943,34501,35975,36601,37159,37277,37358,37409,37442,37461,37491,37807,39268,40134,41178,41481,41701,41855,41970,42054,42179,42525,43452,43562,44120,44214,44435,44531,44608,44656,44688,44714,44774,44848,45118,45234,45300,45395,45599,45717,45800,45855,45884,45934,46060,46178,46255,46305,46381,46494,46662,46719,46762,46806,46894,47002,47081,47121,47162,47206,47297,47395,47480,47521,47610,47679,47760,47794,47817,47847,47868,47948,48015,48151,48296,48370,48434,48485,48506,48528,48552,48587,48640,49129,49476,49551,49612,49663,49687,49700,49728,49900,49979,51122,51876,51923,51968,52019,52055,52070,52090,52319,53243,53483,53723,54021,54139,54208,54259,54287,54330,54393,54978,55844,56172,56475,56588,56665,56716,56751,56776,56838,57213,57591,58149,58899,59120,59324,59478,59596,59730,59876,60258,60325,60519,60822,60906,61082,61178,61259,61308,61340,61365,61412,61510,61808,61934,62003,62098,62318,62426,62478,62516,62559,62616,62784,62897,62973,63023,63100,63218,63344,63394,63442,63511,63639,63757,63817,63857,63891,63920,64016,64090,64246,64343,64477,64553,64630,64664,64691,64714,64740,64795,64957,65150,65274,65328,65397,65448,65471,65494,65529,65566,65877,66192,66416,66451,66509,66560,66582,66610,66682,66959,66984,67062,67180,67348,67413,67471,67506,67533,67547,67561,67943,68035,68151,68371,68472,68541,68594,68627,68666,68698,68808,69366,69460,69681,69777,69854,69902,69934,69960,70020,70130,70400,70703,71060,71236,71440,71608,71736,71825,71900,71934,72017,72135,72356,72420,72596,72709,72818,72860,72887,72925,72977,73085,73305,73400,73469,73595,73893,73991,74038,74073,74127,74196,74364,74460,74536,74595,74660,74854,74964,75015,75081,75155,75273,75374,75434,75478,75508,75555,75693,75725,75785,75860,75944,76009,76086,76138,76159,76184,76217,76241,76282,76329,76400,76452,76521,76577,76611,76646,76662,76685,76732,76823,76941,77056,77108,77153,77188,77204,77219,77389,77453,77518,77631,77785,77850,77911,77943,77975,77995,78373,78613,78692,78818,79022,79123,79187,79233,79260,79314,79381,79575,79878,79962,80138,80234,80315,80364,80396,80421,80506,80632,80930,81151,81467,81643,81863,82031,82119,82188,82215,82257,82366,82479,82655,82719,82940,83058,83141,83175,83204,83259,83342,83460,83664,83759,83825,83941,84211,84285,84326,84375,84453,84529,84683,84779,84856,84889,84967,85077,85100,85146,85195,85249,85364,85465,85544,85573,85596,85648,85663,85685,85738,85773,85859,85924,86005,86057,86083,86095,86107,86133,86185,86266,86331,86417,86452,86505,86527,86542,86594,86617,86646,86725,86826,86941,86995,87044,87090,87113,87223,87301,87334,87411,87507,87661,87737,87815,87864,87905,87979,88249,88365,88431,88526,88730,88848,88931,88986,89015,89049,89132,89250,89471,89535,89711,89824,89933,89975,90002,90071,90159,90327,90547,90723,91039,91260,91558,91684,91769,91794,91826,91875,91956,92052,92228,92312,92615,92809,92876,92930,92957,93003,93067,93168,93372,93498,93577,93817,94195,94215,94247,94279,94340,94405,94559,94672,94737,94801,94971,94986,95002,95037,95082,95134,95249,95367,95458,95505,95528,95544,95579,95613,95669,95738,95790,95861,95908,95949,95973,96006,96031,96052,96104,96181,96246,96330,96405,96465,96497,96635,96682,96712,96756,96816,96917,97035,97109,97175,97226,97336,97530,97595,97654,97730,97826,97994,98063,98117,98152,98199,98297,98595,98721,98790,98885,99105,99213,99265,99303,99330,99372,99481,99594,99770,99834,100055,100173,100256,100290,100365,100454,100582,100750,100954,101130,101487,101790,102060,102170,102230,102256,102288,102336,102413,102509,102730,102824,103382,103492,103524,103563,103596,103649,103718,103819,104039,104155,104247,104629,104643,104657,104684,104719,104777,104842,105010,105128,105206,105232,105508,105580,105608,105630,105681,105739,105775,105999,106314,106624,106661,106696,106719,106742,106793,106862,106916,107041,107234,107395,107450,107476,107499,107526,107560,107637,107713,107847,107945,108100,108174,108270,108299,108333,108373,108433,108551,108679,108748,108796,108846,108972,109090,109167,109217,109293,109406,109574,109631,109674,109712,109764,109872,110092,110187,110256,110382,110680,110778,110825,110850,110882,110931,111012,111108,111284,111368,111671,111865,111933,112315,112460,112594,112712,112866,113070,113292,114041,114599,114978,115352,115414,115439,115474,115525,115602,115715,116019,116346,117213,117797,117860,117903,117931,117982,118051,118169,118467,118708,118947,119871,120100,120120,120135,120171,120222,120267,120314,121068,122211,122290,122462,122490,122503,122527,122578,122639,122715,123061,123550,123603,123638,123662,123684,123705,123756,123820,123894,124039,124175,124242,124322,124343,124373,124396,124430,124511,124580,124669,124710,124795,124893,124984,125028,125069,125109,125188,125296,125384,125428,125471,125528,125696,125809,125885,125935,126012,126130,126256,126306,126335,126390,126473,126591,126795,126890,126956,127072,127342,127416,127476,127502,127534,127582,127659,127755,127976,128070,128628,128738,129665,130012,130136,130220,130335,130489,130709,131012,132056,132922,134383,134699,134729,134748,134781,134832,134913,135031,135589,136215,139782,142039,142127,142133,142153,142186,142221,142275,142589,144611,144982,145988,146122,146131,146140,146176,146229,146279,146471,147398,147455,147527,147611,147625,147636,147660,147708,147786,147884,148266,148312,148353,148376,148394,148403,148424,148480,148563,148632,148707,148757,148840,148892,148919,148940,148963,149015,149124,149181,149250,149294,149382,149490,149569,149609,149650,149694,149785,149883,149968,150003,150057,150126,150294,150390,150466,150525,150590,150784,150894,150948,150975,151021,151085,151186,151390,151516,151595,151835,152214,152588,152650,152675,152710,152761,152838,152951,153255,153582,154448,156470,157224,157448,157519,157605,157720,157888,158186,158744,160218};
bool check(int x){
    if(x <= 9) return x == 7;
    int t = 0;
    for(int i = 1; x >= 10; i *= 10){
        t += i * abs(x % 100 / 10 - x % 10);
        x /= 10;
    }
    return check(t);
}
int calc(int n){
    int t = n / 1000000,sum = 0;
    for(int i = t * 1000000 + 1; i <= n; i ++) sum += check(i);
    return s[t] + sum;
}
int main(){
    // long long s = 0;
    // for(int i = 1; i <= 1e9; i ++){
    //     s += check(i);
    //     if(i % 1000000 == 0) printf("%lld,",s);
    // }
    //打表
    cin >> l >> r;
    cout << calc(r) - calc(l - 1) << endl;
    return 0;
}
哈希冲突

非常神奇的一道题,预处理出所有模数小于等于 n \sqrt{n} n 的答案。询问时若模数小于等于 n \sqrt{n} n ,直接输出,若大于 n \sqrt{n} n ,则最多有不超过 n \sqrt{n} n 个数有贡献,修改时只需暴力修改,总复杂度 O ( n n ) O(n\sqrt{n}) O(nn )

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 2e5 + 50;
int n,m,x,y,a[maxn],s[450][450];
char type;
int read(){
    int x = 0;
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
    return x;
}
int main(){
    n = read(),m = read();
    for(int i = 1; i <= n; i ++){
        a[i] = read();
        for(int j = 1; j * j <= n; j ++) s[j][i % j] += a[i];
    }
    while(m --){
        cin >> type;
        x = read(),y = read();
        if(type == 'A'){
            y %= x;
            if(x * x <= n) printf("%d\n",s[x][y]);
            else{
                int s = 0;
                for(int i = y; i <= n; i += x) s += a[i];
                printf("%d\n",s);
            }
        }else{
            for(int i = 1; i * i <= n; i ++) s[i][x % i] += y - a[x];
            a[x] = y;
        }
    }
    return 0;
}
[NOI2011]道路修建

洛谷随机跳题跳到的sb题,居然是蓝的,而且还是NOI的题,估计是个人都会做

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 1e6 + 50;
int n,x,y,z,cnt,last[maxn],size[maxn];
long long ans;
struct edge{
	int v,w,nxt;
}e[2 * maxn];
int read(){
	int x = 0;
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + (c ^ 48),c = getchar();
	return x;
}
void insert(int x,int y,int z){
	cnt ++,e[cnt].v = y,e[cnt].w = z,e[cnt].nxt = last[x],last[x] = cnt;
}
void dfs(int u,int fa){
	size[u] = 1;
	for(int i = last[u]; i; i = e[i].nxt){
		int v = e[i].v;
		if(v == fa) continue;
		dfs(v,u);
		size[u] += size[v],ans += 1ll * abs(n - 2 * size[v]) * e[i].w;
	}
}
int main(){
	n = read();
	for(int i = 1; i < n; i ++){
		x = read(),y = read(),z = read();
		insert(x,y,z),insert(y,x,z);
	}
	dfs(1,0);
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值