zoukankan      html  css  js  c++  java
  • 【NOIp2019模拟】题解

    T1:

    显然一定会询问nn
    考虑如果能求得每个点的前缀异或和 就可以解出整个序列了

    知道了sl,srs_l,s_r之间一个,就可以一次询问[l+1,r][l+1,r]求出另外一个
    考虑把rrll连边,所有点向00连边
    那最后其实要的就是整个图联通的代价
    每个点代价设为前缀异或和

    问题就变成了最小异或生成树
    最高位往最低位贪心就可以了

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
        static char ibuf[RLEN],*ib,*ob;
        (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ob==ib)?EOF:*ib++;
    }
    #define gc getchar
    inline int read(){
        char ch=gc();
        int res=0,f=1;
        while(!isdigit(ch))f^=ch=='-',ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    #define ll long long
    #define re register
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define cs const
    const int mod=1e9+7;
    inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
    inline void Add(int &a,int b){a=add(a,b);}
    inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
    inline void Dec(int &a,int b){a=dec(a,b);}
    inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
    inline void Mul(int &a,int b){a=mul(a,b);}
    inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
    inline void chemx(ll &a,ll b){a<b?a=b:0;}
    inline void chemn(ll &a,ll b){a>b?a=b:0;}
    cs int N=100005,Log=31;
    int son[N*Log][2],siz[N*Log],tot;
    vector<int> p[N*Log];
    #define lc son[u][0]
    #define rc son[u][1]
    void insert(int v){
    	int u=0;
    	for(int i=Log-1;~i;i--){
    		int t=(v&(1<<i))?1:0;
    		if(!son[u][t])son[u][t]=++tot;
    		u=son[u][t],p[u].pb(v);
    	}
    }
    inline ll query(int u,int v,int dep){
    	ll res=0;
    	for(int i=dep;~i;i--){
    		int t=(v&(1<<i))?1:0;
    		if(son[u][t])u=son[u][t];
    		else u=son[u][t^1],res+=1<<i;
    	}
    	return res;
    }
    ll build(int u,int dep){
    	ll res=0,mn=1e9;
    	if(lc)res+=build(lc,dep-1);
    	if(rc)res+=build(rc,dep-1);
    	if(lc&&rc){
    		int a,b;
    		if(p[lc].size()>p[rc].size())a=lc,b=rc;
    		else a=rc,b=lc;
    		for(int &v:p[b])chemn(mn,query(a,v,dep-1));
    		res+=mn+(1<<dep);
    	}
    	return res;
    }
    int n,a[N];
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++)a[i]=read()^a[i-1];
    	for(int i=0;i<=n;i++)insert(a[i]);
    	cout<<build(0,Log-1);
    }
    

    T2:

    考虑一个显然的dpdp
    f[i][j][s]f[i][j][s]表示长度为ii,值模kkjjSS限制的数每个%3\%3为多少的状态

    显然有f[a+b][i][j]=(x10b+y)%k=i,pq=jf[a][x][p]f[b][y][q]f[a+b][i][j]=sum_{(x*10^{b}+y)\%k=i,poplus q=j}f[a][x][p]*f[b][y][q]
    oplus为三进制下不进位加法
    由于没有前置0的限制
    可以直接倍增dpdp30pts30pts

    然后第一维xx可以把位置先处理出来
    第一维是一个循环卷积
    第二维是一个三进制FWTFWT
    用石家庄的工人阶级队伍那道题的做法就可以

    然后相当于是一个高维卷积
    做法是相当于一个矩阵
    先把行转点值
    然后把每一列提出来转点值
    然后把2个矩阵对应点乘起来
    再把列转回去,行转回去

    吐槽一句:
    考场上的时候已经把高维卷积推出来了
    但是FWTFWT写挂了,把一个a2a2写成a1a1
    然后没看出来
    就没去写FFTFFT

    下午改题的时候limlim开小又调了一下午
    我真的是好难啊

    #include<bits/stdc++.h>
    using namespace std;
    #define gc getchar
    inline int read(){
        char ch=gc();
        int res=0,f=1;
        while(!isdigit(ch))f^=ch=='-',ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    #define ll long long
    #define re register
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define cs const
    const int mod=998244353,G=3;
    inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
    inline void Add(int &a,int b){a=add(a,b);}
    inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
    inline void Dec(int &a,int b){a=dec(a,b);}
    inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
    inline void Mul(int &a,int b){a=mul(a,b);}
    inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
    inline int ksm(int a,ll b,int Mod){
    	int res=1;
    	for(;b;b>>=1,a=1ll*a*a%Mod)
    		if(b&1)res=1ll*res*a%Mod;
    	return res;
    }
    inline void chemx(int &a,int b){a<b?a=b:0;}
    inline void chemn(int &a,int b){a>b?a=b:0;}
    cs int N=555,C=730;
    int S,k,bin[N],sta,num,vis[N];
    ll n;
    struct plx{
    	int x,y;
    	plx(int _x=0,int _y=0):x(_x),y(_y){}
    	friend inline plx operator +(cs plx &a,cs plx &b){
    		return plx(add(a.x,b.x),add(a.y,b.y));
    	}
    	friend inline plx operator -(cs plx &a,cs plx &b){
    		return plx(dec(a.x,b.x),dec(a.y,b.y));
    	}
    	friend inline plx operator *(cs plx &a,cs plx &b){
    		return plx(dec(mul(a.x,b.x),mul(a.y,b.y)),dec(add(mul(a.x,b.y),mul(a.y,b.x)),mul(a.y,b.y)));
    	}
    	friend inline plx operator *(cs plx &a,cs int &b){
    		return plx(mul(a.x,b),mul(a.y,b));
    	}
    	void operator+=(cs plx &b){*this=*this+b;}
    	void operator-=(cs plx &b){*this=*this-b;}
    	void operator*=(cs plx &b){*this=*this*b;}
    	void operator*=(int b){Mul(x,b),Mul(y,b);}
    };
    plx w1,w2;
    inline void DFT(plx *f,int lim){
    	plx a0,a1,a2;
    	for(int mid=1;mid<lim;mid*=3)
    	for(int i=0;i<lim;i+=(mid*3))
    	for(int j=0;j<mid;j++)
    	a0=f[i+j],a1=f[i+j+mid],a2=f[i+j+mid*2],
    	f[i+j]=a0+a1+a2,f[i+j+mid]=a0+a1*w1+a2*w2,f[i+j+mid*2]=a0+a1*w2+a2*w1;
    }
    inline void IDFT(plx *f,int lim){
    	plx a0,a1,a2;
    	for(int mid=1;mid<lim;mid*=3)
    	for(int i=0;i<lim;i+=(mid*3))
    	for(int j=0;j<mid;j++)
    	a0=f[i+j],a1=f[i+j+mid],a2=f[i+j+mid*2],
    	f[i+j]=a0+a1+a2,f[i+j+mid]=a0+a1*w2+a2*w1,f[i+j+mid*2]=a0+a1*w1+a2*w2;
    	for(int i=0,inv=ksm(lim,mod-2);i<lim;i++)Mul(f[i].x,inv);
    }
    cs int c=12;
    vector<int> w[c+1];
    inline void init_w(){
    	for(int i=1;i<=c;i++)w[i].resize(1<<(i-1));
    	int wn=ksm(G,(mod-1)/(1<<c));
    	w[c][0]=1;
    	for(int i=1;i<(1<<(c-1));i++)w[c][i]=mul(w[c][i-1],wn);
    	for(int i=c-1;i;i--)
    	for(int j=0;j<(1<<(i-1));j++)
    	w[i][j]=w[i+1][j<<1];
    }
    int rev[N<<2],lim;
    inline void init_rev(int k){
    	lim=1;
    	while(lim<=(k*2))lim<<=1;
    	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
    }
    inline void ntt(plx *f,int kd){
    	plx a0,a1;
    	for(int i=0;i<lim;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
    	for(int mid=1,l=1;mid<lim;mid<<=1,l++)
    	for(int i=0;i<lim;i+=(mid<<1))
    	for(int j=0;j<mid;j++)
    	a0=f[i+j],a1=f[i+j+mid]*w[l][j],f[i+j]=a0+a1,f[i+j+mid]=a0-a1;
    	if(kd==-1){
    		reverse(f+1,f+lim);
    		for(int i=0,inv=ksm(lim,mod-2);i<lim;i++)f[i]=f[i]*inv;
    	}
    }
    inline void mul(plx *tmp,plx *a,plx *b,ll len){
    	static plx A[N<<1],B[N<<1];
    	int mo=ksm(10,len,k);
    	for(int i=0;i<lim;i++)A[i]=B[i]=plx(0,0);
    	for(int i=0;i<k;i++)A[i*mo%k]+=a[i],B[i]=b[i];
    	ntt(A,1),ntt(B,1);
    	for(int i=0;i<lim;i++)A[i]*=B[i];
    	ntt(A,-1);
    	for(int i=k;i<lim;i++)A[i%k]+=A[i];
    	for(int i=0;i<k;i++)tmp[i]=A[i];
    }
    plx res[N<<2];
    inline plx LpMul(plx *f,ll b){
    	for(int i=0;i<k;i++)res[i]=plx(0,0);
    	res[0].x=1;
    	for(ll len=1;b;b>>=1,mul(f,f,f,len),len*=2)
    	if(b&1)mul(res,res,f,len);
    	return res[0];
    }
    plx f[N][C],A[N<<2],F[C];
    char s[N];
    int main(){
    	cin>>n,k=read(),init_w(),init_rev(k);
    	bin[0]=1;w1=plx(0,1),w2=plx(mod-1,mod-1);
    	for(int i=1;i<=9;i++)bin[i]=bin[i-1]*3;
    	scanf("%s",s);
    	S=strlen(s);sta=pow(3,S);
    	for(int i=0;i<S;i++)vis[s[i]-'0']=++num;
    	for(int i=0;i<=9;i++)f[i%k][bin[vis[i]]/3].x+=1;
    	for(int i=0;i<k;i++)DFT(f[i],sta);
    	for(int i=0;i<sta;i++){
    		for(int j=0;j<k;j++)
    		A[j]=f[j][i];
    		F[i]=LpMul(A,n);
    	}
    	IDFT(F,sta);
    	cout<<F[0].x<<'
    ';
    }
    

    T3:

    树的哈希显然就找在重心为根乱搞一波哈希

    然后设f[i][j]f[i][j]表示在AA中边ii的儿子(相当于带了个顺序),子树哈希情况为jj的方案数
    再记一个gg表示BB中当前点几个子树选择情况为kk的方案数
    然后xjbxjb记忆化dpdp一波就完了

    不过由于同构子树可能重复计数
    题解是把状态从大往小计算,然后强制BB中相同的要依次选

    数组ff要开够

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
        static char ibuf[RLEN],*ib,*ob;
        (ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ob==ib)?EOF:*ib++;
    }
    #define gc getchar
    inline int read(){
        char ch=gc();
        int res=0,f=1;
        while(!isdigit(ch))f^=ch=='-',ch=gc();
        while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
        return f?res:-res;
    }
    #define ll long long
    #define re register
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define cs const
    #define bg begin
    const int mod=1e9+7;
    inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
    inline void Add(int &a,int b){a=add(a,b);}
    inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
    inline void Dec(int &a,int b){a=dec(a,b);}
    inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
    inline void Mul(int &a,int b){a=mul(a,b);}
    inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
    inline void chemx(int &a,int b){a<b?a=b:0;}
    inline void chemn(int &a,int b){a>b?a=b:0;}
    cs int N=2005,M=14,bas=131,mod1=4178981348;
    vector<int> e1[N],e2[N],e3[N],son1[N],h[N];
    map<ll,int> mp;
    int n,m,rt1,rt2,siz[N],son[N],id[N],t[N];
    int vis[N][N],f[N*2][N],num,tot,ans;
    void dfs(int u,int fa){
    	siz[u]=1,son[u]=0;
    	for(int &v:e2[u]){
    		if(v==fa)continue;
    		dfs(v,u);
    		siz[u]+=siz[v];
    		son[u]=max(son[u],siz[v]);
    	}
    	son[u]=max(son[u],m-siz[u]);
    	if(son[u]<son[rt1])rt1=u,rt2=0;
    	else if(son[u]==son[rt1])rt2=u;
    }
    void HasT(int u,int fa){
    	ll has=0;
    	for(int &v:e3[u]){
    		if(v==fa)continue;
    		HasT(v,u);
    		son1[u].pb(t[v]);
    	}
    	sort(son1[u].bg(),son1[u].end());
    	for(int &x:son1[u])has=(has*bas^x)%mod;
    	if(!mp.count(has))h[++tot]=son1[u],mp[has]=tot;
    	t[u]=mp[has];
    }
    int calc(int u,int fa,int tt){
    	if(!vis[u][fa])vis[u][fa]=++num;
    	int id=vis[u][fa];
    	if(f[id][tt])return f[id][tt];
    	vector<int> g;g.resize(1<<h[tt].size());
    	g[0]=1;
    	for(int &v:e1[u]){
    		if(v==fa)continue;
    		for(int s=1<<h[tt].size();~s;s--)if(g[s])
    		for(int k=0;k<h[tt].size();k++)
    		if(!(s&(1<<k))&&(!k||(s&(1<<(k-1)))||h[tt][k]!=h[tt][k-1]))
    		Add(g[s+(1<<k)],mul(g[s],calc(v,u,h[tt][k])));
    	}
    	f[id][tt]=g[(1<<h[tt].size())-1];
    	return f[id][tt];
    }
    int main(){
    	n=read();
    	for(int i=1;i<n;i++){
    		int u=read(),v=read();
    		e1[u].pb(v),e1[v].pb(u);
    	}
    	m=read();
    	for(int i=1;i<m;i++){
    		int u=read(),v=read();
    		e2[u].pb(v),e2[v].pb(u);
    	}
    	son[0]=m,dfs(1,0);
    	if(rt2){
    		if(rt1>rt2)swap(rt1,rt2);
    		for(int i=1;i<=m;i++)
    			for(int &v:e2[i]){
    				if(i<v&&(i!=rt1||v!=rt2))e3[i].pb(v),e3[v].pb(i);
    			}
    		m++,e3[m].pb(rt1),e3[rt1].pb(m);
    		e3[m].pb(rt2),e3[rt2].pb(m),rt1=m;
    	}
    	else for(int i=1;i<=m;i++)
    	for(int &v:e2[i])if(i<v)e3[v].pb(i),e3[i].pb(v);
    	HasT(rt1,0);
    	if(rt2){
    		for(int i=1;i<=n;i++)
    		for(int &v:e1[i])if(i<v){
    			Add(ans,mul(calc(i,v,h[t[m]][0]),calc(v,i,h[t[m]][1])));
    			if(h[t[m]][0]!=h[t[m]][1])
    			Add(ans,mul(calc(i,v,h[t[m]][1]),calc(v,i,h[t[m]][0])));
    		}
    	}
    	else for(int i=1;i<=n;i++)Add(ans,calc(i,0,t[rt1]));
    	cout<<ans;
    }
    
  • 相关阅读:
    设计模式——设计原则与思想总结
    SQL——性能优化篇(下)
    计算机组成原理——入门篇
    SQL——性能优化篇(中)
    SQL——性能优化篇(上)
    设计模式——规范与重构(下)
    设计模式——规范与重构(上)
    编译原理——实现一门脚本语言 应用篇
    编译原理——实现一门脚本语言 原理篇(下)
    设计模式——设计原则实战
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328614.html
Copyright © 2011-2022 走看看