A
求个异或前缀和然后做完全图最小异或生成树即可。
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
#define lb lower_bound
#define ub upper_bound
#define all(x) begin(x),end(x)
#define sz(x) (int)(x).size()
#define rsz resize
#define pb push_back
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int mod=998244353;
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
const int N=4e6+5;
int n;
vector<int>a;
ll ans=0;
namespace trie{
#define lc (son[p][0])
#define rc (son[p][1])
int P,son[N][2],tot,rt;
inline void init(int dep){
tot=1,rt=1;
son[tot][0]=son[tot][1]=0;
P=dep;
}
inline void insert(int x){
for(ri t,i=P,p=rt;~i;--i){
t=x>>i&1;
if(!son[p][t]){
son[p][t]=++tot;
son[tot][0]=son[tot][1]=0;
}
p=son[p][t];
}
}
inline int query(int x){
int ret=0;
for(ri t,i=P,p=rt;~i;--i){
t=x>>i&1;
if(son[p][t])p=son[p][t];
else p=son[p][t^1],ret|=1<<i;
}
return ret;
}
#undef lc
#undef rc
}
inline void solve(int dep,vector<int>a){
if(a.size()<2||dep==-1)return;
vector<int>tl,tr;
for(ri i=sz(a)-1;~i;--i){
if(a[i]>>dep&1)tr.push_back(a[i]);
else tl.push_back(a[i]);
}
if(tl.size()&&tr.size()){
int mn=0x3f3f3f3f;
trie::init(dep);
for(ri i=sz(tl)-1;~i;--i)trie::insert(tl[i]);
for(ri i=sz(tr)-1;~i;--i)mn=min(mn,trie::query(tr[i]));
ans+=mn;
}
solve(dep-1,tl),solve(dep-1,tr);
}
int main(){
n=read();
a.push_back(0);
for(ri i=1;i<=n;++i)a.push_back(a.back()^read());
solve(30,a);
cout<<ans;
return 0;
}
B
设
f
i
,
j
,
k
f_{i,j,k}
fi,j,k表示
i
i
i 位整数模
K
K
K 余数为
j
j
j , 被限制的数字出现次数的三进制状态为
j
j
j 的方案数。
显然有递推式
f
T
,
a
,
b
=
∑
A
+
B
=
T
,
(
x
∗
1
0
B
+
y
)
%
K
=
a
,
p
⊕
q
=
b
f
A
,
x
,
p
∗
f
B
,
y
,
q
f_{T,a,b}=\sum\limits_{A+B=T,(x*10^B+y)\%K=a,p\oplus q=b}f_{A,x,p}*f_{B,y,q}
fT,a,b=A+B=T,(x∗10B+y)%K=a,p⊕q=b∑fA,x,p∗fB,y,q
其中
⊕
\oplus
⊕表示三进制异或
这个时候可以通过倍增+
d
p
g
e
t
dp\ get
dp get 到一个比较大众的部分分。然而我写了矩乘快速幂
然后考虑最后一维可以用
3
3
3 进制
F
W
T
FWT
FWT 搞一波,不会的戳这里,这样你可以拿到一个不太大众的部分分
再观察第二个式子,哎哎这个不是一个
F
F
T
FFT
FFT 吗? 你稳了
好的恭喜你爆了标算。
对于两个矩阵,我们先把每一行用 3 3 3 进制 F W T FWT FWT 转点值, 然后用 F F T FFT FFT 把每一列多项式乘法, 然后再转回去即可。
别忘了处理那个10的幂
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int mod=998244353;
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
struct F{
int x,y;
F(int x=0,int y=0):x(x),y(y){}
friend inline F operator+(F a,F b){return F(add(a.x,b.x),add(a.y,b.y));}
friend inline F operator-(F a,F b){return F(dec(a.x,b.x),dec(a.y,b.y));}
friend inline F operator*(F a,F b){return F(dec(mul(a.x,b.x),mul(a.y,b.y)),dec(add(mul(a.x,b.y),mul(a.y,b.x)),mul(b.y,a.y)));}
friend inline void operator+=(F&a,F b){a=a+b;}
friend inline void operator-=(F&a,F b){a=a-b;}
friend inline void operator*=(F&a,F b){a=a*b;}
}w0,w1,w2,W1[21],W2[21],invv[21];
typedef vector<F> poly;
const int N=250,M=729;
ll T;
int K;
inline void FWT(poly&a,int n,int type){
F a0,a1,a2;
for(ri i=1;i<n;i*=3)for(ri j=0,len=i*3;j<n;j+=len)
for(ri k=0;k<i;++k){
a0=a[j+k],a1=a[j+k+i],a2=a[j+k+i*2];
a[j+k]=a0+a1+a2;
a[j+k+i]=a0+a1*w1+a2*w2;
a[j+k+i*2]=a0+a1*w2+a2*w1;
if(type==-1)swap(a[j+k+i],a[j+k+i*2]);
}
if(~type)return;
F iv=F(ksm(n,mod-2),0);
for(ri i=0;i<n;++i)a[i]*=iv;
}
vector<int>rev[21];
int lim=1,tim=0;
inline void init_ntt(){
W1[20]=F(ksm(3,(mod-1)>>21),0);
W2[20]=F(ksm(W1[20].x,mod-2),0);
for(ri i=19;~i;--i)W1[i]=F(mul(W1[i+1].x,W1[i+1].x),0),W2[i]=F(mul(W2[i+1].x,W2[i+1].x),0);
invv[0]=F(1,0);
for(ri i=1,iv=mod+1>>1;i<21;++i)invv[i]=F(mul(invv[i-1].x,iv),0);
}
inline void init(const int&up){
lim=1,tim=0;
while(lim<up)lim<<=1,++tim;
if(rev[tim].size())return;
rev[tim].resize(lim);
for(ri i=1;i<lim;++i)rev[tim][i]=(rev[tim][i>>1]>>1)|((i&1)<<(tim-1));
}
inline void ntt(poly&a,int type){
for(ri i=0;i<lim;++i)if(i<rev[tim][i])swap(a[i],a[rev[tim][i]]);
F a0,a1,mt,Mt;
for(ri i=1,t=0;i<lim;i<<=1,++t)for(ri j=0,len=i<<1;j<lim;j+=len){
mt=F(1,0),Mt=~type?W1[t]:W2[t];
for(ri k=0;k<i;++k,mt*=Mt)a0=a[j+k],a1=a[j+k+i]*mt,a[j+k]=a0+a1,a[j+k+i]=a0-a1;
}
if(~type)return;
for(ri i=0;i<lim;++i)a[i]*=invv[tim];
}
inline poly operator*(poly a,poly b){
int n=a.size(),m=b.size(),t=n+m-1;
if(t<=32){
poly c(K);
for(ri i=0;i<n;++i)for(ri j=0;j<m;++j)c[(i+j)%K]+=a[i]*b[j];
return c;
}
init(t);
a.resize(lim),ntt(a,1);
b.resize(lim),ntt(b,1);
for(ri i=0;i<lim;++i)a[i]*=b[i];
ntt(a,-1);
for(ri i=K;i<lim;++i)a[i%K]+=a[i];
return a.resize(K),a;
}
inline poly mul(poly t,poly b,int md){
poly a(t.size());
for(ri i=0;i<K;++i)a[i*md%K]+=t[i];
return a*b;
}
inline poly operator^(poly a,ll p){
poly ret(K);
ret[0]=F(1,0);
for(int l=10%K;p;p>>=1,a=mul(a,a,l),(l*=l)%=K)if(p&1)ret=mul(ret,a,l);
return ret;
}
char s[10];
int pw[10],vs[10],len;
poly f[N],a,res;
int main(){
#ifdef ldxcaicai
freopen("lx.in","r",stdin);
#endif
w0=F(1,0),w1=F(0,1),w2=F(mod-1,mod-1);
init_ntt();
cin>>T>>K;
pw[0]=1;
for(ri i=1;i<10;++i)pw[i]=pw[i-1]*3;
scanf("%s",s+1),len=strlen(s+1);
for(ri i=1;i<=len;++i)vs[s[i]-'0']=i;
for(ri i=0;i<K;++i)f[i].resize(pw[len]);
for(ri i=0;i<10;++i)++f[i%K][pw[vs[i]]/3].x;
for(ri i=0;i<K;++i)FWT(f[i],pw[len],1);
a.resize(K);
res.resize(pw[len]);
for(ri i=0;i<pw[len];++i){
for(ri j=0;j<K;++j)a[j]=f[j][i];
res[i]=(a^T)[0];
}
FWT(res,pw[len],-1);
cout<<res[0].x;
return 0;
}
C
最联赛的一道吧 毕竟A考的不是联赛知识点
我们先对
B
B
B 树做树哈希,然后枚举
A
A
A 树的根拿到
A
A
A 树上
D
P
DP
DP。
转移要用状压
d
p
dp
dp ,注意要判断重复的子树QwQ
代码:
#include<bits/stdc++.h>
#define konjak_ldx 23112
#define ri register int
#define fi first
#define se secnod
#define lb lower_bound
#define ub upper_bound
#define all(x) begin(x),end(x)
#define sz(x) (int)(x).size()
#define rsz resize
#define pb push_back
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int mod=1e9+7;
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:(a-=mod);}
inline void Dec(int&a,int b){(a-=b)<0?(a+=mod):a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
typedef long long ll;
const int N=2005,M=13;
int n,m,all,rt,rt1,rt2,msz,siz[M];
vector<int>e[N],g[M+5],h[M];
map<ll,int>S;
void getroot(int p,int fa){
siz[p]=1;
int ms=0;
for(ri i=0,v;i<h[p].size();++i){
if((v=h[p][i])==fa)continue;
getroot(v,p),siz[p]+=siz[v],ms=max(ms,siz[v]);
}
ms=max(ms,all-siz[p]);
if(ms<msz){
rt1=p,rt2=0;
msz=ms;
}
else if(ms==msz)rt2=p;
}
int vl[M],sig=0;
vector<int>Vl[M];
inline void gethash(int p,int fa){
vector<int>t;
for(ri i=0,v;i<g[p].size();++i){
if((v=g[p][i])==fa)continue;
gethash(v,p),t.push_back(vl[v]);
}
sort(all(t));
ll ss=0;
for(ri i=0;i<sz(t);++i)ss=ss*konjak_ldx+t[i];
vl[p]=S.count(ss)?S[ss]:(Vl[S[ss]=++sig]=t,sig);
}
int tot=0,f[N<<3][M],vs[N][N];
bool vis[N<<3][M];
int DP(int p,int fa,int Tree){
if(!vs[p][fa])vs[p][fa]=++tot;
int id=vs[p][fa];
if(vis[id][Tree])return f[id][Tree];
vis[id][Tree]=1;
int tim=Vl[Tree].size(),lim=1<<tim;
vector<int>tmp(lim);
tmp[0]=1;
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fa)continue;
for(ri j=lim-1;~j;--j)if(tmp[j]){
for(ri k=0;k<tim;++k){
if(j>>k&1)continue;
if((!k)||(Vl[Tree][k]!=Vl[Tree][k-1])||(j>>(k-1)&1)){
Add(tmp[j|(1<<k)],mul(tmp[j],DP(v,p,Vl[Tree][k])));
}
}
}
}
return f[id][Tree]=tmp[lim-1];
}
int main(){
#ifdef ldxcaicai
freopen("lx.in","r",stdin);
#endif
n=read();
for(ri i=1,u,v;i<n;++i){
u=read(),v=read();
e[u].push_back(v);
e[v].push_back(u);
}
m=read();
for(ri i=1,u,v;i<m;++i){
u=read(),v=read();
h[u].push_back(v);
h[v].push_back(u);
}
all=msz=m,rt1=rt2=0,getroot(1,0);
int ans=0;
if(rt2){
++m;
rt=m;
for(ri u=1,v;u<m;++u){
for(ri i=0;i<h[u].size();++i){
v=h[u][i];
if((u==rt1&&v==rt2)||(u==rt2&&v==rt1)){
g[m].push_back(u);
g[u].push_back(m);
continue;
}
g[u].push_back(v);
}
}
gethash(rt,0);
for(ri u=1,v;u<=n;++u){
for(ri i=0;i<e[u].size();++i){
v=e[u][i];
if(u>v)continue;
Add(ans,mul(DP(u,v,Vl[vl[rt]][0]),DP(v,u,Vl[vl[rt]][1])));
}
}
}
else{
rt=rt1;
for(ri u=1;u<=m;++u)g[u]=h[u];
gethash(rt,0);
for(ri i=1;i<=n;++i)Add(ans,DP(i,0,vl[rt]));
}
cout<<ans;
return 0;
}