NOI模拟20220529
T1 s1mple
容斥,先转化成没有0的限制,最后高维查分搞回来
然后发现变成了许多链,于是fwt再卷起来复杂度就对了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=20;
const ull bas=131;
int n,u,v,m,b[N][N];char ch[N];
int res[1<<17],ans[1<<17];
unordered_map<ull,int> mp;int hf[N];
int sm[1<<17],f[1<<17][18];
int a[18][1<<17],g[1<<17];
void fwt(int *a){
fo(i,0,n-1)fo(s,0,u)if(s>>i&1)a[s]+=a[s^(1<<i)];
}
void ifwt(int *a){
fo(i,0,n-1)fo(s,0,u)if(s>>i&1)a[s]-=a[s^(1<<i)];
}
signed main(){
freopen("s1mple.in","r",stdin);
freopen("s1mple.out","w",stdout);
// cerr<<(sizeof(f)+sizeof(g)>>20)<<endl;
n=read();u=(1<<n)-1;v=(1<<n-1)-1;
fo(i,1,n){
scanf("%s",ch+1);
fo(j,1,n)b[i][j]=ch[j]-'0';
}
fo(s,0,u)sm[s]=sm[s>>1]+(s&1);
fo(i,1,n)f[1<<i-1][i]=1;
fo(t,1,u){
fo(i,1,n)if(f[t][i]){
a[sm[t]][t]+=f[t][i];
fo(j,1,n)if(!(t>>j-1&1)&&b[i][j]){
f[t|(1<<j-1)][j]+=f[t][i];
}
}
}
fo(i,1,17)fwt(a[i]);
fo(s,0,v){
memset(hf,0,sizeof(hf));int las=1;
fo(i,1,n-1)if(!(s>>i-1&1)){
hf[i-las+1]++;las=i+1;
}hf[n-las+1]++;
ull hs=0;fo(i,1,n)hs=hs*131+hf[i];
if(mp.find(hs)!=mp.end()){
res[s]=mp[hs];continue;
}
fo(i,0,u)g[i]=1;
fo(i,1,n)fo(j,1,hf[i]){
fo(k,0,u)g[k]*=a[i][k];
}
ifwt(g);res[s]=g[u];
mp[hs]=res[s];
}
fo(i,0,n-2)fo(s,0,v)if(!(s>>i&1))res[s]-=res[s^(1<<i)];
m=read();
while(m--){
scanf("%s",ch+1);
int ss=0;
fo(i,1,n-1)ss|=(ch[i]-'0')<<i-1;
printf("%lld\n",res[ss]);
}
}
T2 s2mple
考场上只会\(n^2logn\),沈老师有一个期望根号log的做法,但是我多次询问然而懵逼结束,现在回了
其实是个扫描线,我们把所有询问离线在后缀树节点上
正解要转化一下,变成在这个字符串前面后面添字符,最后成为子串的方案数
在前面添加就是fail树中的子树,后面就SAM上的dp
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*t;
}
const int N=4e5+5;
int n,m;char s[N];
struct SAM{
struct POT{
int son[26],fail;
int len;
}tr[N*2];
int seg,las;
SAM(){seg=las=1;}
void ins(int c){
int np=++seg,p=las;las=np;
tr[np].len=tr[p].len+1;
while(p&&!tr[p].son[c])tr[p].son[c]=np,p=tr[p].fail;
if(!p)tr[np].fail=1;
else {
int q=tr[p].son[c];
if(tr[q].len==tr[p].len+1)tr[np].fail=q;
else {
int nq=++seg;
tr[nq]=tr[q];tr[nq].len=tr[p].len+1;
tr[np].fail=tr[q].fail=nq;
while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
}
}
}
}sam;
struct E{int to,nxt;}e[N*2];
int head[N*2],rp,ps[N];
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
int dp[N*2],sm[N*2],bc[N],wo[N*2];
void sol(){
fo(i,1,sam.seg)bc[sam.tr[i].len]++;
fo(i,1,n)bc[i]+=bc[i-1];
fo(i,1,sam.seg)wo[bc[sam.tr[i].len]--]=i;
fu(i,sam.seg,1){
fo(j,0,25)dp[wo[i]]+=dp[sam.tr[wo[i]].son[j]];
dp[wo[i]]++;
}
}
int fa[N*2][21];
void dfs(int x,int f){
// if(x==3)cerr<<f<<endl;
fa[x][0]=f;sm[x]=0;
fo(i,1,20)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].to;dfs(y,x);
sm[x]+=sm[y]+(sam.tr[y].len-sam.tr[x].len)*dp[y];
}
}
int work(int l,int r){
int now=ps[r],ret=0,ln=r-l+1;
// cerr<<now<<" "<<fa[now][0]<<" "<<sam.tr[fa[now][0]].len<<" "<<ln<<endl;
fu(i,20,0)if(fa[now][i]&&sam.tr[fa[now][i]].len>=ln)now=fa[now][i];
// cerr<<sam.tr[now].son[1]<<endl;
// cerr<<now<<" "<<sam.tr[now].len<<" "<<sam.tr[sam.tr[now].fail].len<<" "<<ln<<endl;
ret=sm[now]+(sam.tr[now].len-ln+1)*dp[now];
return ret;
}
signed main(){
freopen("s2mple.in","r",stdin);
freopen("s2mple.out","w",stdout);
n=read();m=read();
scanf("%s",s+1);
fo(i,1,n)sam.ins(s[i]-'a'),ps[i]=sam.las;
fo(i,2,sam.seg){
// cerr<<sam.tr[i].fail<<" "<<i<<endl;
add_edg(sam.tr[i].fail,i);
}
sol();dfs(1,0);
while(m--){
int l=read(),r=read();
printf("%lld\n",work(l,r));
}
}
QQ:2953174821