2018CCPC桂林 B. Array Modify
题意:
求
m
(
1
e
9
)
m(1e9)
m(1e9)轮操作:
A
[
i
]
=
(
∑
j
=
i
m
i
n
(
i
+
L
−
1
,
n
)
A
[
j
]
)
m
o
d
P
A[i]=(\sum_{j=i}^{min(i+L-1,n)}A[j])\mod P
A[i]=(∑j=imin(i+L−1,n)A[j])modP
后的数组。
注意到新数组中
A
′
A'
A′的值由差值固定的一段
A
A
A累计得来。
于是每次操作都是一次多项式乘法,
C
[
x
]
=
∑
i
=
0
x
A
[
i
]
∗
B
[
x
−
i
]
C[x]=\sum_{i=0}^xA[i]*B[x-i]
C[x]=∑i=0xA[i]∗B[x−i]。
考虑构造
B
[
x
−
i
]
B[x-i]
B[x−i]。
由式子可知,
B
[
0
]
B[0]
B[0]到
B
[
L
−
1
]
B[L-1]
B[L−1]这连续一段都是1,其他是0。
而注意到,当
A
A
A到末尾的时候,由于长度关系,不能由完整的一段长度为L的更新而来。所以考虑将A翻转。
于是我们的A和B就成为了:
[an-1,an-2,…,a4,a3,a2,a1,a0]
[1,1,1,…,1,1,0,0,0,…,0]
结果序列就是:
[an-1, an-2+an-1, an-3+an-2+an-1, …, aL+1+…+a3+a2, aL+…+a2+a1, aL-1+…+a1+a0]
就是想要的结果序列的翻转。
于是问题转化为求
A
−
1
×
B
m
A^{-1}\times B^m
A−1×Bm。
多项式快速幂带两个log,说过不了。
那么我们考虑用生成函数简化
B
m
B^m
Bm。
注意到
B
=
1
+
x
+
x
2
+
.
.
.
+
x
L
−
1
B=1+x+x^2+...+x^{L-1}
B=1+x+x2+...+xL−1。
是个等比数列。那么我们改写成
1
−
x
L
1
−
x
\frac{1-x^L}{1-x}
1−x1−xL。
现在要求这个东西的
m
m
m次幂。
发现上下求幂都可以用二项式展开。
也就是分子是
∑
i
=
0
m
i
n
(
n
−
1
,
m
)
(
m
i
)
(
−
1
)
i
x
L
i
\sum_{i=0}^{min(n-1,m)}\binom{m}{i}(-1)^ix^{Li}
∑i=0min(n−1,m)(im)(−1)ixLi
分母是
∑
i
=
0
m
i
n
(
n
−
1
,
m
)
(
m
i
)
(
−
1
)
i
x
i
\sum_{i=0}^{min(n-1,m)}\binom{m}{i}(-1)^ix^i
∑i=0min(n−1,m)(im)(−1)ixi
于是分子分母的幂次都是一个多项式了。
于是将分母求逆即可。
//
// Created by Artist on 2021/10/22.
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 1e5+4;
const int mod = 998244353;
const int g = 3;
int A[maxn<<2],B[maxn<<2],C[maxn<<2],C2[maxn<<2],tmp[maxn<<2];
int qpow(int a, int n) {
int ans=1;
while(n) {
if(n&1) ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
n>>=1;
}
return ans;
}
int rev[maxn<<2];
void ntt(int *a,int n,int t) {
for(int i=1;i<n;++i) {
rev[i] = (rev[i>>1]>>1)|(i&1?n>>1:0);
if(i>rev[i]) swap(a[i],a[rev[i]]);
}
for(int i=2;i<=n;i<<=1) {
int wn=qpow(g,(mod-1)/i);
if(t==-1) wn=qpow(wn,mod-2);
for(int j=0;j<n;j+=i) {
int w=1;
for(int k=j;k<j+i/2;++k) {
int u=a[k];
int v=1ll*a[k+i/2]*w%mod;
a[k]=(1ll*u+v)%mod;
a[k+i/2]=(1ll*u-v+mod)%mod;
w=1ll*w*wn%mod;
}
}
}
if(t==-1) {
ll inv=qpow(n,mod-2);
for(int i=0;i<n;++i) a[i]=1ll*a[i]*inv%mod;
}
}
void polyinv(int f[],int h[],int n) {
fill(f,f+n+n,0);
f[0] = qpow(h[0],mod-2);
for(int t=2;t<=n;t<<=1) {
const int t2=t<<1;
copy(h,h+t,tmp);
fill(tmp+t,tmp+t2,0);
ntt(f,t2,1);
ntt(tmp,t2,1);
for(int i=0;i!=t2;++i)
f[i]=1ll*f[i]*(2-1ll*f[i]*tmp[i]%mod+mod)%mod;
ntt(f,t2,-1);
fill(f+t,f+t2,0);
}
}
signed main() {
io();
int ca=0;
int t;cin>>t;
while(t--) {
int n,m,L;cin>>n>>L>>m;
int lim;
for(lim=1;lim<(n<<1);lim<<=1);
for(int i=0;i<lim;++i) A[i]=B[i]=C[i]=0;
for(int i=0;i<n;++i) cin>>tmp[i];
for(int i=0;i<n;++i) A[i]=tmp[n-i-1];
for(int i=0,c=1,f=1;i<=m&&1ll*i*L<n;++i) {
B[i*L]=1ll*c*f%mod;
c=1ll*c*(m-i)%mod*qpow(i+1,mod-2)%mod;
f=mod-f;
}
for(int i=0,c=1,f=1;i<=m&&i<n;++i) {
C[i]=1ll*c*f%mod;
c=1ll*c*(m-i)%mod*qpow(i+1,mod-2)%mod;
f=mod-f;
}
int len;
for(len=1;len<n;len<<=1);
polyinv(C2,C,len);
ntt(B,lim,1);
ntt(C2,lim,1);
ntt(A,lim,1);
for(int i=0;i<lim;++i) B[i]=1ll*B[i]*C2[i]%mod;
ntt(B,lim,-1);
fill(B+len,B+len+len,0); // 必须清空(取模),不然会错,调了很久这里
ntt(B,lim,1);
for(int i=0;i<lim;++i) B[i]=1ll*B[i]*A[i]%mod;
ntt(B,lim,-1);
cout<<"Case "<<++ca<<": ";
for(int i=n-1;~i;--i) cout<<B[i]<<" ";
cout<<endl;
}
}
多项式快速幂板子
多项式快速幂加强版
求
B
(
x
)
≡
A
(
x
)
k
m
o
d
P
B(x)\equiv A(x)^k\mod P
B(x)≡A(x)kmodP,
k
∈
1
0
1
0
5
k\in 10^{10^5}
k∈10105
不能快速幂,因为这个
k
k
k不是模
P
−
1
P-1
P−1意义下。
B
(
x
)
≡
A
(
x
)
k
m
o
d
P
B(x)\equiv A(x)^k\mod P
B(x)≡A(x)kmodP
B
(
x
)
≡
e
k
ln
A
(
x
)
m
o
d
P
B(x)\equiv e^{k\ln A(x)}\mod P
B(x)≡eklnA(x)modP
所以先对
A
(
x
)
A(x)
A(x)进行模
P
P
P意义下的对数,再乘上模
P
P
P意义下的
k
k
k,再求指数。
以上做法的前提条件是
A
[
0
]
=
1
A[0]=1
A[0]=1,因为取对数需要这样。
在加强版中,这个条件不满足。
发现
A
k
=
(
A
A
[
0
]
)
k
×
A
[
0
]
k
A^k=(\frac{A}{A[0]})^k\times A[0]^k
Ak=(A[0]A)k×A[0]k
因为
A
[
0
]
A[0]
A[0]是个常数,所以后面的
A
[
0
]
k
A[0]^k
A[0]k的
k
k
k要欧拉降幂。括号内多项式幂次的不用,像普通版那样算就行。
如果
A
[
0
]
=
=
0
A[0]==0
A[0]==0这个做法就挂了。
发现
A
k
=
(
A
x
t
)
k
×
x
t
k
A^k=(\frac{A}{x^t})^k\times x^{tk}
Ak=(xtA)k×xtk
所以把多项式
A
A
A左移掉那些系数为0的项。最后再右移上
t
k
tk
tk项即可。
普通版:
//
// Created by Artist on 2021/10/23.
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
#define reg register
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 1e5+5;
const int P = 998244353;
const int g = 3;
string s;
inline int read() {
reg char ch=getchar();
reg int x=0,f=1;
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*f;
}
inline int readm() {
reg char ch=getchar();
reg ll x=0,f=1;
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=((x<<3)+(x<<1)+ch-'0')%P;
ch=getchar();
}
return x*f;
}
inline int qpow(int a,int n) {
int ans=1;
while(n) {
if(n&1) ans=1ll*ans*a%P;
a=1ll*a*a%P;
n>>=1;
}
return ans;
}
void ntt(int a[],int n,int t) {
static int rev[maxn<<2];
for(int i=1;i<n;++i) {
rev[i] = (rev[i>>1]>>1)|(i&1?n>>1:0);
if(i>rev[i]) swap(a[i],a[rev[i]]);
}
for(int i=2;i<=n;i<<=1) {
int wn=qpow(g,(P-1)/i);
if(t==-1) wn=qpow(wn,P-2);
for(int j=0;j<n;j+=i) {
int w=1;
for(int k=j;k<j+i/2;++k) {
int u=a[k];
int v=1ll*a[k+i/2]*w%P;
a[k]=(1ll*u+v)%P;
a[k+i/2]=(1ll*u-v+P)%P;
w=1ll*w*wn%P;
}
}
}
if(t==-1) {
ll inv=qpow(n,P-2);
for(int i=0;i<n;++i) a[i]=1ll*a[i]*inv%P;
}
}
void polyinv(int f[],int h[],int n) {
static int tmp[maxn<<2];
int len;
for(len=1;len<n;len<<=1);
fill(f,f+len+len+2,0);
fill(tmp,tmp+len+1,0);
f[0] = qpow(h[0],P-2);
for(int t=2;t<=len;t<<=1) {
const int t2=t<<1;
copy(h,h+t,tmp);
fill(tmp+t,tmp+t2,0);
ntt(f,t2,1);
ntt(tmp,t2,1);
for(int i=0;i!=t2;++i)
f[i]=1ll*f[i]*(2-1ll*f[i]*tmp[i]%P+P)%P;
ntt(f,t2,-1);
fill(f+t,f+t2,0);
}
fill(f+n,f+len+1,0);
}
void polyln(int f[],int h[],int n) {
static int tmp2[maxn<<2],tmp3[maxn<<2];
int lim;
for(lim=1;lim<(n<<1);lim<<=1);
fill(tmp2,tmp2+lim,0);
fill(tmp3,tmp3+lim,0);
fill(f,f+lim,0);
polyinv(tmp3,h,n);
for(int i=1;i<n;++i) tmp2[i-1]=1ll*h[i]*i%P;
ntt(tmp2,lim,1);
ntt(tmp3,lim,1);
for(int i=0;i<lim;++i) tmp3[i]=1ll*tmp3[i]*tmp2[i]%P;
ntt(tmp3,lim,-1);
for(int i=1;i<n;++i) f[i]=1ll*qpow(i,P-2)*tmp3[i-1]%P;
fill(f+n,f+lim,0);
}
void polyexp(int f[],int h[],int n) {
static int tmp4[maxn<<2];
if(n==1) {f[0]=1;return;}
int lim;
for(lim=1;lim<(n<<1);lim<<=1);
fill(tmp4,tmp4+lim,0);
polyexp(f,h,n+1>>1),polyln(tmp4,f,n);
tmp4[0]=(1ll*h[0]+1-tmp4[0]+P)%P;
for(int i=1;i<n;++i) tmp4[i]=(1ll*h[i]-tmp4[i]+P)%P;
ntt(tmp4,lim,1),ntt(f,lim,1);
for(int i=0;i<lim;++i) f[i]=1ll*f[i]*tmp4[i]%P;
ntt(f,lim,-1);
fill(f+n,f+lim,0);
}
int A[maxn<<2],B[maxn<<2],C[maxn<<2];
signed main() {
int n=read(),k=readm();
for(int i=0;i<n;++i) A[i]=read();
polyln(B,A,n);
for(int i=0;i<n;++i) B[i]=1ll*B[i]*k%P;
polyexp(C,B,n);
for(int i=0;i<n;++i) printf("%d ",C[i]);
}
加强版:
//
// Created by Artist on 2021/10/23.
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
#define reg register
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 1e5+5;
const int P = 998244353;
const int g = 3;
inline int read() {
reg char ch=getchar();
reg int x=0,f=1;
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)) {
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*f;
}
inline int qpow(int a,int n) {
int ans=1;
while(n) {
if(n&1) ans=1ll*ans*a%P;
a=1ll*a*a%P;
n>>=1;
}
return ans;
}
void ntt(int a[],int n,int t) {
static int rev[maxn<<2];
for(int i=1;i<n;++i) {
rev[i] = (rev[i>>1]>>1)|(i&1?n>>1:0);
if(i>rev[i]) swap(a[i],a[rev[i]]);
}
for(int i=2;i<=n;i<<=1) {
int wn=qpow(g,(P-1)/i);
if(t==-1) wn=qpow(wn,P-2);
for(int j=0;j<n;j+=i) {
int w=1;
for(int k=j;k<j+i/2;++k) {
int u=a[k];
int v=1ll*a[k+i/2]*w%P;
a[k]=(1ll*u+v)%P;
a[k+i/2]=(1ll*u-v+P)%P;
w=1ll*w*wn%P;
}
}
}
if(t==-1) {
ll inv=qpow(n,P-2);
for(int i=0;i<n;++i) a[i]=1ll*a[i]*inv%P;
}
}
void polyinv(int f[],int h[],int n) {
static int tmp[maxn<<2];
int len;
for(len=1;len<n;len<<=1);
fill(f,f+len+len+2,0);
fill(tmp,tmp+len+1,0);
f[0] = qpow(h[0],P-2);
for(int t=2;t<=len;t<<=1) {
const int t2=t<<1;
copy(h,h+t,tmp);
fill(tmp+t,tmp+t2,0);
ntt(f,t2,1);
ntt(tmp,t2,1);
for(int i=0;i!=t2;++i)
f[i]=1ll*f[i]*(2-1ll*f[i]*tmp[i]%P+P)%P;
ntt(f,t2,-1);
fill(f+t,f+t2,0);
}
fill(f+n,f+len+1,0);
}
void polyln(int f[],int h[],int n) {
static int tmp2[maxn<<2],tmp3[maxn<<2];
int lim;
for(lim=1;lim<(n<<1);lim<<=1);
fill(tmp2,tmp2+lim,0);
fill(tmp3,tmp3+lim,0);
fill(f,f+lim,0);
polyinv(tmp3,h,n);
for(int i=1;i<n;++i) tmp2[i-1]=1ll*h[i]*i%P;
ntt(tmp2,lim,1);
ntt(tmp3,lim,1);
for(int i=0;i<lim;++i) tmp3[i]=1ll*tmp3[i]*tmp2[i]%P;
ntt(tmp3,lim,-1);
for(int i=1;i<n;++i) f[i]=1ll*qpow(i,P-2)*tmp3[i-1]%P;
fill(f+n,f+lim,0);
}
void polyexp(int f[],int h[],int n) {
static int tmp4[maxn<<2];
if(n==1) {f[0]=1;return;}
int lim;
for(lim=1;lim<(n<<1);lim<<=1);
fill(tmp4,tmp4+lim,0);
polyexp(f,h,n+1>>1),polyln(tmp4,f,n);
tmp4[0]=(1ll*h[0]+1-tmp4[0]+P)%P;
for(int i=1;i<n;++i) tmp4[i]=(1ll*h[i]-tmp4[i]+P)%P;
ntt(tmp4,lim,1),ntt(f,lim,1);
for(int i=0;i<lim;++i) f[i]=1ll*f[i]*tmp4[i]%P;
ntt(f,lim,-1);
fill(f+n,f+lim,0);
}
int A[maxn<<2],B[maxn<<2],C[maxn<<2];
string s;
signed main() {
int n=read();
int k1=0,k2=0,k3=0;cin>>s;
for(int i=0;i<s.length();++i) {
k1=(10ll*k1+s[i]-'0')%P;
k2=(10ll*k2+s[i]-'0')%(P-1);
if(i<6) k3=10*k3+s[i]-'0';
}
int pos=-1,a0;
for(int i=0;i<n;++i) {
A[i]=read();
if(pos==-1&&A[i]) {
a0=A[i];
pos=i;
}
}
// 只有A[0]==0的时候才需要转移,不然不用转移
// A[0]!=1的时候需要除以A[0],最后再乘回A[0]^{k mod P-1}
// 全为0
if(pos==-1) {
for(int i=0;i<n;++i) printf("0 ");
return 0;
}
// 左移
for(int i=0;i<n;++i) {
if(i+pos<n) A[i]=A[i+pos];
else A[i]=0; // 移完后清空
}
// 除掉A[0]
int a0inv = qpow(a0,P-2);
for(int i=0;i<n;++i) A[i]=1ll*A[i]*a0inv%P;
polyln(B,A,n);
for(int i=0;i<n;++i) B[i]=1ll*B[i]*k1%P;
polyexp(C,B,n);
// 右移
int dis=min(1ll*n,1ll*k3*pos);
for(int i=n-1;~i;--i) {
if(i-dis>=0) C[i]=C[i-dis];
else C[i]=0;
}
int mul = qpow(a0,k2);
for(int i=0;i<n;++i) C[i]=1ll*C[i]*mul%P;
for(int i=0;i<n;++i) printf("%d ",C[i]);
}
2017CCPC女生赛 Innumerable Ancestors
树剖+树上倍增
把A的节点的祖先全部标记,对每个B查询其祖先中最深的有标记的,返回这个深度。
然后还原树,把A删掉,等待下次样例。
因为cinTLE了两次-。-
//
// Created by artist on 2021/10/23.
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
#define pii pair<int,int>
#define int long long
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
int n,m;
const int maxn = 1e5+5;
vector<int> G[maxn];
int f[24][maxn];
int sz[maxn],dfn,son[maxn],tp[maxn],num[maxn],dep[maxn];
int tr[maxn<<2],lzy[maxn<<2];
int ql,qr,opt;
void dfs0(int u,int fa) {
sz[u]=1;
dep[u]=dep[fa]+1;
for(auto v:G[u]) {
if(v-fa) {
dfs0(v,u),sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
}
void dfs1(int u,int pa,int fa) {
num[u]=++dfn;
tp[u]=pa;
f[0][u]=fa;
if(son[u]) dfs1(son[u],pa,u);
for(auto v:G[u]) if(v-fa&&v-son[u]) dfs1(v,v,u);
}
void build(int l,int r,int rt) {
if(l==r) {
tr[rt] = lzy[rt] = 0;
return;
}
int mid=l+r>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
tr[rt] = lzy[rt] = 0;
}
int query(int l,int r,int rt) {
if(l==r) {
return tr[rt];
}
int mid=l+r>>1;
if(lzy[rt]) {
lzy[rt<<1]+=lzy[rt];
lzy[rt<<1|1]+=lzy[rt];
tr[rt<<1]+=lzy[rt]*(mid-l+1);
tr[rt<<1|1]+=lzy[rt]*(r-mid);
lzy[rt]=0;
}
if(ql<=mid) return query(l,mid,rt<<1);
else return query(mid+1,r,rt<<1|1);
}
void add(int l,int r,int rt) {
if(ql<=l&&qr>=r) {
tr[rt]+=opt*(r-l+1);
lzy[rt]+=opt;
return;
}
int mid=l+r>>1;
if(lzy[rt]) {
lzy[rt<<1]+=lzy[rt];
lzy[rt<<1|1]+=lzy[rt];
tr[rt<<1]+=lzy[rt]*(mid-l+1);
tr[rt<<1|1]+=lzy[rt]*(r-mid);
lzy[rt]=0;
}
if(ql<=mid) add(l,mid,rt<<1);
if(qr>mid) add(mid+1,r,rt<<1|1);
tr[rt]=tr[rt<<1]+tr[rt<<1|1];
}
int a[maxn],b[maxn];
// 检测这个点是否有值
bool check(int u) {
ql=num[u];
if(query(1,n,1)) return 1;
else return 0;
}
int solve(int u) {
if(check(u)) return dep[u];
for(int j=20;~j;--j)
if(f[j][u]&&!check(f[j][u])) u=f[j][u];
return dep[f[0][u]];
}
signed main() {
while(~scanf("%lld",&n)) {
scanf("%lld",&m);
for(int i=1;i<=n;++i) G[i].clear();
for(int i=1;i<=n;++i) son[i]=0;
dfn=0;
for(int i=1;i<n;++i) {
int u,v;scanf("%lld%lld",&u,&v);
G[u].pb(v);
G[v].pb(u);
}
dfs0(1,0);
dfs1(1,1,0);
for(int j=1;j<=20;++j) for(int i=1;i<=n;++i) f[j][i] = f[j-1][f[j-1][i]];
build(1,n,1);
while(m--) {
int k1;scanf("%lld",&k1);
opt=1;
for(int i=1;i<=k1;++i) {
scanf("%lld",&a[i]);
int u=a[i];
while(u) {
ql=num[tp[u]],qr=num[u];
add(1,n,1);
u = f[0][tp[u]];
}
}
int k2;scanf("%lld",&k2);
int ret=0;
for(int i=1;i<=k2;++i) {
scanf("%lld",&b[i]);
ret = max(ret,solve(b[i]));
}
opt=-1;
for(int i=1;i<=k1;++i) {
int u=a[i];
while(u) {
ql=num[tp[u]],qr=num[u];
add(1,n,1);
u = f[0][tp[u]];
}
}
printf("%lld\n",ret);
}
}
}
莫比乌斯反演及变形
公式:
f
(
n
)
=
∑
d
∣
n
g
(
d
)
f(n)=\sum_{d|n}g(d)
f(n)=∑d∣ng(d)
g
(
n
)
=
∑
d
∣
n
f
(
n
d
)
∗
μ
(
d
)
g(n)=\sum_{d|n}f(\frac{n}{d})*\mu(d)
g(n)=∑d∣nf(dn)∗μ(d)
变形:
倍数和
写法1:
f
(
i
)
=
∑
d
=
1
⌊
n
i
⌋
g
(
d
∗
i
)
f(i)=\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}g(d*i)
f(i)=∑d=1⌊in⌋g(d∗i)
g
(
i
)
=
∑
d
=
1
⌊
n
i
⌋
f
(
d
∗
i
)
μ
(
d
)
g(i)=\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}f(d*i)\mu(d)
g(i)=∑d=1⌊in⌋f(d∗i)μ(d)
写法2:
f
(
i
)
=
∑
i
∣
d
,
d
≤
n
g
(
d
)
f(i)=\sum_{i|d,d\leq n}g(d)
f(i)=∑i∣d,d≤ng(d)
g
(
i
)
=
∑
i
∣
d
,
d
≤
n
f
(
d
)
μ
(
d
i
)
g(i)=\sum_{i|d,d\leq n}f(d)\mu(\frac{d}{i})
g(i)=∑i∣d,d≤nf(d)μ(id)
数论分块:
首先有一性质
⌊
n
k
d
⌋
=
⌊
⌊
n
k
⌋
d
⌋
\lfloor\frac{n}{kd}\rfloor=\lfloor \frac{\lfloor \frac{n}{k}\rfloor}{d}\rfloor
⌊kdn⌋=⌊d⌊kn⌋⌋
2017 CCPC女生赛 Judicious Strategy
博弈(SG)+爆搜
算是第二次接触这种题,这下该会了吧。。
//
// Created by Artist on 2021/10/25.
//
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) {
std::cout << a << ' ';
dbg(args...);
}
void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 30000;
const int inf = 2e9;
struct SG {
int wintag,myscore,opscore;
SG(int a=1,int b=inf,int c=0):wintag(a),myscore(b),opscore(c){}
bool operator < (const SG &b) const {
if(wintag!=b.wintag) return wintag<b.wintag;
if(opscore!=b.opscore) return opscore>b.opscore;
return myscore<b.myscore;
}
}sg[maxn];
int n,tot;
string input[33];
unordered_map<string,int> ok;
string reok[maxn];
int score[maxn];
vector<int> G[maxn];
void init() {
tot = 0;
ok.clear();
for(int i=0;i<maxn;++i) {
G[i].clear();
sg[i].wintag = -1;
}
}
int get_score(string tt) {
int maxx=0,sum=0,len=tt.length(),occ=0;
for(int i=0;i<len;++i) {
sum += tt[i]-'a'+1;
maxx = max(maxx,tt[i]-'a'+1);
}
for(int i=1;i<=n;++i) {
if(input[i].find(tt)!=string::npos) occ++;
}
return maxx*sum+occ;
}
void readin() {
for(int i=1;i<=n;++i) cin>>input[i];
for(int i=1;i<=n;++i) {
int len=input[i].length();
for(int j=0;j<len;++j) {
string temp = "";
for(int k=j;k<len;++k) {
temp += input[i][k];
if(ok[temp]) continue;
ok[temp] = ++tot;
reok[tot] = temp;
score[tot] = get_score(temp);
}
}
}
}
void build_graph() {
for(int i=1;i<=tot;++i) {
int len=reok[i].length();
if(len==1) {
G[0].pb(i);
continue;
}
string temp1 = reok[i].substr(1,len-1);
if(ok[temp1]) G[ok[temp1]].pb(i);
string temp2 = reok[i].substr(0,len-1);
if(ok[temp2]) G[ok[temp2]].pb(i);
}
}
SG dfs(int now) {
if(sg[now].wintag!=-1) return sg[now];
if(!G[now].size()) return sg[now]=SG(0,0,score[now]);
SG worst;
for(int i=0;i<G[now].size();++i) {
SG nex=dfs(G[now][i]);
if(nex<worst) worst=nex;
}
return sg[now]=SG(worst.wintag^1,worst.opscore,worst.myscore+score[now]);
}
signed main() {
while(~scanf("%d",&n)) {
init();
readin();
build_graph();
SG ans = dfs(0);
if(ans.wintag) printf("Alice\n");
else printf("Bob\n");
printf("%d %d\n",ans.myscore,ans.opscore);
}
}
2019CCPC哈尔滨 E. Exchanging Gifts
用超级快读就过了的一道题,非常卡常
#include <bits/stdc++.h>
//#define endl '\n'
#define lose {printf("NO\n");return;}
#define win {printf("YES\n");return;}
#define all(A) (A).begin(),(A).end()
#define FOR(I, A, B) for (int I = (A); I <= (B); ++I)
#define PER(I, A, B) for (int I = (A); I >= (B); --I)
#define DB(A) cout<<(A)<<endl
#define lson k*2
#define rson k*2+1
#define fi first
#define se second
#define PB push_back
#define Pair pair<int,int>
#define MP make_pair
#define ll long long
#define ull unsigned long long
//#define int ll
using namespace std;
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
void dbg() { std::cout << " #\n"; }
template<typename T, typename...Args>
void dbg(T a, Args...args) { std::cout << a << ' '; dbg(args...); }
template <typename T> void print(T x) {
if (x < 0) { putchar('-'); print(x); return ; }
if (x >= 10) print(x / 10);
putchar((x % 10) + '0');
}
//var
const int maxn=2e6+10;
//head
int n;
int typ[maxn];
vector<int> oper[maxn];
int son[maxn][2];
bool vis[maxn];
int ru[maxn];
ll val[maxn];
int cnt;
unordered_map<int,int> mp2;
ll summ[maxn];
queue<int>q;
#define getcha() (S==T&&(T=(S=fsr)+fread(fsr,1,1<<15,stdin),S==T)?EOF:*S++)
char fsr[1<<15],*S=fsr,*T=fsr;
inline int read(){
int r(0),w(1);char ch=getcha();
while(ch>=58 || ch<=47){
w=(ch=='-'?-1:1);r=(r<<3)+(r<<1)+ch-48;
ch=getcha();
}
while(ch<=57 && ch>=48){
r=(r<<3)+(r<<1)+ch-48;
ch=getcha();
}
return r*w;
}
void bfs1()
{
FOR(i,1,n) vis[i]=0;
vis[n]=1;
q.push(n);
while (!q.empty())
{
int now=q.front();q.pop();
if(son[now][0]==0) continue;
for(int i=0;i<2;++i) {
int to=son[now][i];
if (!vis[to])//only visit each node once
{
vis[to]=1;
q.push(to);
}
}
}
//rebuild
FOR(i,1,n) son[i][0]=son[i][1]=0;
FOR(i,1,n) if (vis[i])//truly useful
{
if (typ[i]==2)
{
son[i][0]=oper[i][0];
ru[oper[i][0]]++;
son[i][1]=oper[i][1];
ru[oper[i][1]]++;
}
}
}
void topu()
{
q.push(n);
val[n]=1;
while (!q.empty())
{
int now=q.front();q.pop();
if(son[now][0]==0) continue;
for(int i=0;i<2;++i) {
int to=son[now][i];
ru[to]--;
val[to]+=val[now];
if (!ru[to])
{
q.push(to);
}
}
}
}
void solve()
{
n=read();
FOR(i,1,n)
{
oper[i].clear();
son[i][0]=son[i][1]=0;
ru[i]=0;
vis[i]=0;
val[i]=0;
summ[i]=0;
}
mp2.clear();
cnt=0;
FOR(i,1,n)
{
int op;
op=read();
typ[i]=op;//record type
if (op==1)
{
int k=read();
FOR(j,1,k)
{
int x=read();
if(!mp2[x]) mp2[x]=++cnt;
oper[i].PB(mp2[x]);//record reading info
}
}
else
{
int x=read(),y=read();
oper[i].PB(x);//record reading info
oper[i].PB(y);
son[i][0]=x;
son[i][1]=y;
}
}
bfs1();
topu();
FOR(i,1,n) if (typ[i]==1&&vis[i])
{
for (auto ele : oper[i])
{
summ[ele] += val[i];
}
}
ll sum=0;
ll maxx=0;
for(int i=1;i<=cnt;++i) {
sum += summ[i];
maxx = max(maxx,summ[i]);
}
ll ans;
if (maxx>sum/2)
{
ans=sum-maxx+sum-maxx;
}
else
{
ans=sum;
}
printf("%lld\n",ans);
}
signed main()
{
// freopen("read.txt", "r", stdin);
// freopen("ans.txt", "w", stdout);
int TestCase = read();
while (TestCase--)
{
solve();
}
}