• 2022722 #16 P7275 & P5362 & uoj425


    海伊生日呀。

    typora 导出不了 pdf 可以查看 print spooler 是否启用,然后关闭所有 typora 进程继续尝试。

    040 P7275 计树

    我们需要钦定出若干条编号连续且长度大于 \(1\) 的链,然后将这些链拼在一起。实际上就是将 \([1,n]\) 划分成若干个长度大于 \(1\) 的段,然后将这些段拼接。

    由于我们无法保证链之间不能合并,可以先用 Prufer 计算合并方案数,再采用集合划分容斥。(这个命名实际上不严谨,这种容斥方式只是类似集合划分容斥)

    令容斥系数为 \(F(x)\),第 \(i\) 项系数对应长度为 \(i\) 的段的容斥系数。

    注意集合划分容斥中的“合并等价类”在本题中会变为“拼接连续段”,所以我们应得到:

    \[[x^k](\frac{1}{1-F}-1)=[k>1]\\\frac{1}{1-F}-1=\frac{x^2}{1-x}\\F=\frac{x^2}{x^2-x+1} \]

    那么我们可以直接列出答案的生成函数:

    \[\sum_{t\geqslant 1}[x^n](\sum_{i\geqslant 1} nix^iF_i)^t\\=[x^n](\frac{1}{1-\sum_{i\geqslant 1}nix^iF_i}-1) \]

    多项式求逆即可,复杂度 \(O(n\log n)\)

    似乎可以通过线性递推得到更低的复杂度。

    #include<stdio.h>
    #include<vector>
    using namespace std;
    const int maxn=1<<18,maxk=19,mod=998244353,G=3,invG=(mod+1)/3;
    typedef vector<int>poly;
    int n,m,lim;
    int btf[maxn],w[maxk][maxn][2];
    int ksm(int a,int b){
    	int res=1;
    	while(b){
    		if(b&1)
    			res=1ll*res*a%mod;
    		a=1ll*a*a%mod,b>>=1;
    	}
    	return res;
    }
    void init(){
    	for(int len=2,i=1;i<maxk;len<<=1,i++){
    		int o0=ksm(G,(mod-1)/len),o1=ksm(invG,(mod-1)/len);
    		w[i][0][0]=w[i][0][1]=1;
    		for(int j=1;j<len;j++)
    			w[i][j][0]=1ll*w[i][j-1][0]*o0%mod,w[i][j][1]=1ll*w[i][j-1][1]*o1%mod;
    	}
    }
    int getlen(int n){
    	int r=0;
    	while((1<<r)<n)
    		r++;
    	for(int i=0;i<(1<<r);i++)
    		btf[i]=(btf[i>>1]>>1)|((i&1)<<(r-1));
    	return (1<<r);
    }
    void NTT(poly &X,int lim,int opt){
    	X.resize(lim);
    	int *x=X.data();
    	for(int i=0;i<lim;i++)
    		if(i<btf[i])
    			swap(x[i],x[btf[i]]);
    	for(int p=1,l=2;l<=lim;p++,l<<=1)
    		for(int i=0;i<lim;i+=l)
    			for(int j=0;j<(l>>1);j++){
    				int a=x[i+j],b=1ll*x[i+j+(l>>1)]*w[p][j][opt]%mod;
    				x[i+j]=(a+b)%mod,x[i+j+(l>>1)]=(a-b+mod)%mod;
    			}
    	if(opt==1){
    		int v=ksm(lim,mod-2);
    		for(int i=0;i<lim;i++)
    			x[i]=1ll*x[i]*v%mod;
    	}
    }
    void polyinv(poly &x,int deg){
    	if(deg==1){
    		x.resize(1),x[0]=ksm(x[0],mod-2);
    		return ;
    	}
    	poly a=x,b=x;
    	a.resize(deg),polyinv(b,(deg+1)>>1);
    	int lim=getlen(deg<<1);
    	NTT(a,lim,0),NTT(b,lim,0);
    	x.resize(lim);
    	int *X=x.data();
    	for(int i=0;i<lim;i++)
    		X[i]=1ll*b[i]*(2-1ll*a[i]*b[i]%mod+mod)%mod;
    	NTT(x,lim,1),x.resize(deg);
    }
    poly F;
    int main(){
    	scanf("%d",&n),init();
    	F.resize(n+1);
    	for(int i=2;i<=n;i++)
    		F[i]=(i%6==4||i%6==1)? 0:((i%6==2||i%6==3)? 1:(mod-1));
    	for(int i=0;i<=n;i++)
    		F[i]=1ll*(mod-n)*i%mod*F[i]%mod;
    	F[0]=1;
    	polyinv(F,n+1);
    	printf("%d\n",(int)(1ll*F[n]*ksm(1ll*n*n%mod,mod-2)%mod));
    	return 0;
    }
    

    041 P5362 [SDOI2019]连续子序列

    考虑 Thue−Morse 序列的一种生成方式:先构造出长为 \(2^{n-1}\) 的 Thue−Morse 序列,然后将每个 \(0\) 变成 \(01\),每个 \(1\) 变成 \(10\)

    我们想要将 \(S\) 不断“上推”,当 \(|S|\) 到达 \(O(1)\) 级别,我们分类讨论得到答案。

    可以证明对于长度 \(>3\) 的串,“上推”的方案是唯一的,比如 \(1010\) 能变成 \(11,000\),而后面那种不合法。

    于是直接分讨即可,我们分讨要不要把第一个位置单独拿出来。

    复杂度 \(O(|S|(\log |S|+\log k))\)

    #include<stdio.h>
    #include<iostream>
    #include<map>
    using namespace std;
    const int maxn=10005,mod=1000000009;
    int T,tot;
    string s;
    long long k;
    map<string,int>dic;
    map<long long,int>mp[maxn];
    int calc(string s,long long k){
    	if(s.size()==1&&k<=2)
    		return k==0? 1:(k==1? 2:3);
    	if(s.size()==2&&k<=1)
    		return k==0? 1:(s[0]==s[1]? 1:2);
    	if(s.size()==3&&k<=0)
    		return s[0]==s[1]&&s[1]==s[2]? 0:1;
    	if(dic.count(s)==0)
    		dic[s]=++tot;
    	int t=dic[s];
    	if(mp[t].count(k))
    		return mp[t][k];
    	int n=s.size(),res=0,flg=1;
    	for(int i=0;i+1<n;i+=2)
    		flg&=(s[i]!=s[i+1]);
    	if(flg){
    		string tmp="";
    		for(int i=0;i<n;i+=2)
    			tmp=tmp+s[i];
    		res=calc(tmp,s.size()&1? (k/2):((k+1)/2));
    	}
    	flg=1;
    	for(int i=1;i+1<n;i+=2)
    		flg&=(s[i]!=s[i+1]);
    	if(flg){
    		string tmp="";
    		tmp=tmp+(char)(s[0]^1);
    		for(int i=1;i<n;i+=2)
    			tmp=tmp+s[i];
    		res+=calc(tmp,s.size()&1? ((k+1)/2):(k/2));
    	}
    	return mp[t][k]=res%mod;
    }
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		cin>>s,scanf("%lld",&k);
    		printf("%d\n",calc(s,k));
    	}
    	return 0;
    }
    

    042 uoj#425. 【集训队作业2018】strings

    比较经典的复杂度平衡方法。

    首先折半一下,暴力枚举一半的二进制位,得到哪些询问能对答案贡献。一个比较 naive 的想法是用 bitset 存每个询问对应合法答案然后 or 起来,这样复杂度是 \(O(2^{\frac n2}nq+\frac{2^nq}{\omega})\) 的。

    但是可以类似四毛子地分块,每个块处理每个子集对应的 bitset,复杂度就变成了 \(O(2^{\frac n2}(n+\frac{2^B}{\omega})q+\frac{2^nq}{B\omega})\),取 \(B=10\) 即可。

    #include<stdio.h>
    #include<bitset>
    #include<iostream>
    using namespace std;
    const int maxq=105,B=10;
    int n,q,ans,S,T;
    int bl[B+5],br[B+5];
    bitset<1<<15>res,b[maxq],rec[B+5][1<<B];
    string s[maxq];
    int main(){
    	scanf("%d%d",&n,&q),S=1<<(n/2);
    	for(int i=1;i<=q;i++){
    		cin>>s[i];
    		for(int j=0;j<S;j++){
    			int flg=1;
    			for(int k=0;k<n/2;k++)
    				flg&=(s[i][k]=='?'||s[i][k]-48==((j>>k)&1));
    			b[i][j]=flg;
    		}
    	}
    	T=q/B;
    	for(int i=1;i<=T;i++)
    		bl[i]=br[i-1]+1,br[i]=i*B;
    	if(br[T]<q)
    		T++,bl[T]=br[T-1]+1,br[T]=q;
    	for(int i=1;i<=T;i++)
    		for(int j=0;j<1<<(br[i]-bl[i]+1);j++)
    			for(int k=0;k<br[i]-bl[i]+1;k++)
    				if((j>>k)&1)
    					rec[i][j]|=b[bl[i]+k];
    	for(int t=0;t<(1<<(n-n/2));t++){
    		res.reset();
    		for(int i=1;i<=T;i++){
    			int st=0;
    			for(int j=0;j<br[i]-bl[i]+1;j++){
    				int flg=1;
    				for(int k=0;k<n-n/2;k++)
    					flg&=(s[bl[i]+j][n/2+k]=='?'||s[bl[i]+j][n/2+k]-48==((t>>k)&1));
    				st|=(flg<<j);
    			}
    			res|=rec[i][st];
    		}
    		ans+=res.count();
    	}
    	printf("%d\n",ans);
    	return 0;
    }
    

    043 AGC053F ESPers

    很神秘的题啊。

    044 uoj#705. 黄忠庆功宴

    很有趣的题目!

  • 相关阅读:
    thinkphp5 tp5 命名空间 报错 Namespace declaration statement has to be the very first statement in the script
    开启 php 错误 提示 php-fpm 重启 nginx 500错误 解决办法 wdlinux lnmp 一键包 php脚本无法解析执行
    js 设置 cookie 定时 弹出层 提示层 下次访问 不再显示 弹窗 getCookie setCookie setTimeout
    php 二维数组 转字符串 implode 方便 mysql in 查询
    nginx 重启 ps -ef|grep nginx kill -HUP 主进程号
    jquery bootstrap help-block input 表单 提示 帮助 信息
    jquery 倒计时 60秒 短信 验证码 js ajax 获取
    jQuery如何获取同一个类标签的所有的值 遍历
    linux下C语言文件操作相关函数
    gcc,gdb用法
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/16505651.html
Copyright © 2020-2023  润新知