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}
b02≡a0(mod998244353),可以用Cipolla
算法或由原根的次幂遍历模数的完系用BSGS
解出。虽然BSGS
较慢但实现简单,所以这里用的是BSGS
(BSGS
模板在下面)
#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=⌊p1p2−x⌋+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 ap1−bp2=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) x⩾gcd(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 ⌊p1p2−gcd(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(Qnlog2n)? 没仔细算。
#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,i∗106]中的个数,则表中只需要存 1000 1000 1000个数,可以接受。而对于询问 [ A , B ] [A,B] [A,B],我们只需要计算 [ 1 , B ] [1,B] [1,B]中的个数减去 [ 1 , A − 1 ] [1,A - 1] [1,A−1]中的个数即可,则问题转化为求一个区间 [ 1 , n ] [1,n] [1,n]的和。设 n = k ∗ 1 0 6 + b n = k * 10^6 + b n=k∗106+b(其中 0 ⩽ b < 1 0 6 0 \leqslant b < 10 ^ 6 0⩽b<106),则小于等于 k ∗ 1 0 6 k * 10 ^ 6 k∗106的部分已经求出( S k S_k Sk),大于 k ∗ 1 0 6 k * 10 ^ 6 k∗106的部分直接暴力求即可
#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;
}