也许
维护 \(S\) 集合形成的线性基,答案就是 \(2^{n-\rm{rank}}\)
动态维护写一个带删除线性基即可
Code Display
const int N=2e6+10;
int n,Q,ans,nxt[N];
struct Linear_Basis{
int t[40],cnt,b[40];
inline void insert(int v,int tim){
for(int i=30;i>=0;--i) if(v>>i&1){
if(b[i]){
if(t[i]<tim) swap(tim,t[i]),swap(v,b[i]);
v^=b[i];
}else ++cnt,t[i]=tim,b[i]=v,i=0;
}
return ;
}
}B;
unordered_map<int,int> mp;
int opt[N],x[N];
signed main(){
freopen("A.in","r",stdin); freopen("A.out","w",stdout);
n=read(); Q=read();
for(int i=1;i<=Q;++i){
opt[i]=read(); x[i]=read();
if(opt[i]==1){
mp[x[i]]=i;
}else{
nxt[mp[x[i]]]=i;
mp.erase(x[i]);
}
}
for(int i=1;i<=Q;++i) if(opt[i]==1&&!nxt[i]) nxt[i]=Q+1;
for(int i=1;i<=Q;++i){
if(opt[i]==1) B.insert(x[i],nxt[i]);
else{
for(int j=30;j>=0;--j) if(B.t[j]==i){
B.t[j]=B.b[j]=0;
--B.cnt;
}
}
assert(!B.b[30]);
ans^=1ll<<(n-B.cnt);
}
print(ans);
return 0;
}
这就是
设 \(f_{i,S}\) 表示 \(S\) 中的元素分成了 \(i\) 中不同的权值层,转移每次加入一个子集即可
根据实际含义,加入的新集合需要满足 \((R,id)\) 的最小值,对应的元素方案数也就是 \(\min-\rm num\) ,其中 \(\rm num\) 是已经分出来的集合个数
时间复杂度 \(\Theta(n3^n)\)
乍一看是不能通过集合幂级数 \(\exp\) 往下降复杂度的,因为我不会集合幂级数求导
Code Display
int dp[1<<15],mn[1<<15],r[20],g[1<<15],n,m;
signed main(){
freopen("B.in","r",stdin); freopen("B.out","w",stdout);
n=read(); m=read();
rep(i,1,n) r[i]=read()+1;
int U=1<<n; --U;
mn[0]=r[0]=mod;
for(int i=1;i<=U;++i){
int lb=i&(-i);
mn[i]=min(mn[i^lb],r[__builtin_ctz(lb)+1]);
}
while(m--){
int u=read(),v=read();
for(int i=1;i<=U;++i){
bool c1=i>>(u-1)&1;
bool c2=i>>(v-1)&1;
if(c1&&c2) mn[i]=0;
}
}
for(int i=1;i<=U;++i){
int tmp=i;
while(tmp){
int lb=tmp&(-tmp);
int id=__builtin_ctz(lb)+1;
tmp^=lb;
if(r[id]<r[g[i]]) g[i]=id;
}
}
int ans=0;
dp[0]=1;
for(int i=0;i<n;++i){
for(int S=U;~S;--S){
dp[S]=0;
for(int T=S;T;T=(T-1)&S) if(T>>(g[U^(S^T)]-1)&1){
ckadd(dp[S],mul(dp[S^T],max(0ll,mn[T]-i)));
}
}
ckadd(ans,mul(dp[U],i+1));
}
print(ans);
return 0;
}
人生吧
使用 \(e[p^e\ | \ gcd,p^{e+1}\not|\ gcd]=\sum_{e\ge 1}[p^e|gcd]\) 来计算区间元素所包含的某个因子 \(p\) 的贡献
如果现在已知有 \(x\) 个元素唯一分解中 \(p\) 的指数 \(\ge e\) 那么再加入 \(p^e\) 新增的贡献是 \(p^{2^x}\)
此时可以使用莫队维护,注意 \(p\) 的贡献都是 \(p^{2^x}\) 的形式,那么对于所有可行的 \((p,x)\) 预处理出来即可
Code Display
int pri[N],cnt,a[N],n,Q,d[N],bl[N],block;
bool fl[N];
vector<pair<int,int> > Div[N];
struct Query{int l,r,id;}q[N];
vector<int> pw[N],ipw[N];
int ton[N][20],cur=1,ans[N];
int pw2[N];
inline void insert(int id){
for(auto pr:Div[id]){
int p=pr.fir,e=pr.sec;
for(int t=1;t<=e;++t){
ckmul(cur,pw[p][ton[p][t]]);
ton[p][t]++;
}
}
return ;
}
inline void erase(int id){
for(auto pr:Div[id]){
int p=pr.fir,e=pr.sec;
for(int t=1;t<=e;++t){
ton[p][t]--;
ckmul(cur,ipw[p][ton[p][t]]);
}
}
return ;
}
int sum[N];
signed main(){
freopen("C.in","r",stdin); freopen("C.out","w",stdout);
n=1e5;
pw2[0]=1; pw2[1]=2;
for(int i=2;i<=n;++i){
if(!fl[i]) pri[++cnt]=i,d[i]=i;
for(int j=1;i*pri[j]<=n&&j<=cnt;++j){
fl[i*pri[j]]=1; d[i*pri[j]]=pri[j];
if(i%pri[j]==0) break;
}
pw2[i]=mul(pw2[i-1],2,mod-1);
}
for(int i=1;i<=n;++i){
}
n=read(); Q=read(); block=sqrt(Q);
rep(i,1,n){
a[i]=read();
int x=a[i];
while(x>1){
int v=d[x],tim=0;
while(x%v==0) x/=v,tim++;
Div[i].emplace_back(v,tim);
sum[v]++;
}
}
for(int i=1;i<=cnt;++i) if(sum[pri[i]]){
pw[pri[i]].resize(1+sum[pri[i]]);
pw[pri[i]][0]=pri[i];
ipw[pri[i]].resize(1+sum[pri[i]]);
ipw[pri[i]][0]=ksm(pri[i],mod-2);
for(int j=1;j<=sum[pri[i]];++j){
pw[pri[i]][j]=mul(pw[pri[i]][j-1],pw[pri[i]][j-1]);
ipw[pri[i]][j]=mul(ipw[pri[i]][j-1],ipw[pri[i]][j-1]);
}
}
for(int i=1;i<=Q;++i) q[i].l=read(),q[i].r=read(),q[i].id=i,bl[i]=(i-1)/block+1;
sort(q+1,q+Q+1,[&](const Query &a,const Query &b){
if(bl[a.l]==bl[b.l]) return a.r<b.r;
return bl[a.l]<bl[b.l];
});
int l=1,r=0;
for(int i=1;i<=Q;++i){
while(r<q[i].r) insert(++r);
while(l>q[i].l) insert(--l);
while(l<q[i].l) erase(l++);
while(r>q[i].r) erase(r--);
ans[q[i].id]=cur;
}
rep(i,1,Q) print(ans[i]);
return 0;
}