zoukankan      html  css  js  c++  java
  • 并不对劲的马后炮1210

    t1

    题目大意

    有一个有(n)((nleq152501))个节点的有向图,每个节点的出度和入度都是(1),随机选择不重复的(k)个点,求从这(k)个点出发,能走到每一个点的概率,模998244353

    题解

    发现(n)个点中选(k)个共有(C_{n}^{k})个方案,那么只要求出有多少种选点方案使从选中的点能走到每一个点,就能用这个方案数除以(C_{n}^{k})得到答案
    每个节点的出度和入度都是(1)的有向图只由若干个环组成,设一共有(m)个环
    所以当且仅当每一个环上都存在一个选中的点时,能从选中的点走到每一个点
    (f(i,j))表示考虑前(i)个环,选(j)个点,能使每个环上都有选中的点的方案数,(siz(i))表示第(i)个环上有几个点
    则有

    [f(i,j)=sum_{x=max(j-siz(i),1)}^{j-1}f(i-1,x)*C_{siz(i)}^x ]

    设函数$$g_i(x)= 0*x0+sum_{j=1}{min(siz(i),k)}C_{siz(i)}j*xj $$
    设函数(h_i(x))(j)次项的系数为(f(i,j))
    (h_i)(h_{i-1})(g_i)的卷积
    那么方案数就变成了将(g_1),(g_2),……,(g_m)都卷起来后,(k)次项的系数
    发现直接暴力将相邻的两个卷起来可能会被卡
    可以像哈夫曼树那样合并,或进行分治,算出前一半和后一半结果后将这两个结果卷起来

    代码

    我写的是分治的做法

    #include<algorithm>
    #include<cmath>
    #include<complex>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(int i=(x);i>=(y);--i)
    #define maxn 152510
    #define maxm (maxn<<3)
    #define LL long long
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
        return x*f;
    }
    void write(int x)
    {
        if(x==0){putchar('0'),putchar('
    ');return;}
        int f=0;char ch[20];
        if(x<0)putchar('-'),x=-x;
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar('
    ');
        return;
    }
    const LL mod=998244353;
    int n,k,m,r[maxm],len,t,p[maxn],inv[maxn],po[maxn],siz[maxn];
    int a[maxm],b[maxm],cnt,vis[maxn],g[maxn],ing[maxn],nowlen,nown;
    int C(int x,int y){if(x==y)return 1;if(y>x)return 0;return (LL)po[x]*(LL)inv[y]%mod*(LL)inv[x-y]%mod;}
    int mul(int x,int y)
    {
        int ans=1;
        while(y)
        {
            if(y&1)ans=((LL)ans*(LL)x)%mod;
            x=((LL)x*(LL)x)%mod,y>>=1;
        }
        return ans;
    }
    void fntt(int * c,int f)
    {
        rep(i,0,nown-1)r[i]=(r[i>>1]>>1)|((i&1)<<(nowlen-1));
        rep(i,0,nown-1)if(i<r[i])swap(c[i],c[r[i]]);
        for(int i=1;i<nown;i<<=1)
        {
            int wn=mul(3,(mod-1)/(i<<1)),x,y;
            if(f==-1)wn=mul(wn,mod-2);
            for(int j=0;j<nown;j+=(i<<1))
            {
                int w=1;
                rep(k,0,i-1)
                    x=c[j+k]%mod,y=((LL)w*(LL)c[j+i+k])%mod,c[j+k]=(x+y)%mod,c[j+i+k]=(x-y+mod)%mod,w=(LL)w*(LL)wn%mod; 
            }
        }
    	if(f==-1)
    	{
    		int invn=mul(nown,mod-2);
    		rep(i,0,nown-1)c[i]=(LL)c[i]*(LL)invn%mod;
    	}
    }
    vector<int>v[maxn<<2];
    void reset(){rep(i,0,n)vis[i]=siz[i]=0;rep(i,0,(n<<2))v[i].clear();cnt=0;}
    int getsiz(int u){vis[u]=1;if(!vis[p[u]])return getsiz(p[u])+1;else return 1;}
    void getans(int L,int R)
    {
    	if(L==R)
    	{
    		int lim=min(k,siz[L]);
    		v[L].push_back(0);
    		rep(i,1,lim){v[L].push_back(C(siz[L],i));}
    		return;
    	}
    	int mid=(L+R)>>1,lim1,lim2;
    	getans(L,mid),getans(mid+1,R);
    	lim1=v[L].size(),lim2=v[mid+1].size();
    	rep(i,0,lim1-1)a[i]=v[L][i];
    	rep(i,0,lim2-1)b[i]=v[mid+1][i];nowlen=0,nown=1;
    	while(nown-1<lim1+lim2-1)nown<<=1,nowlen++;
    	rep(i,lim1,nown-1)a[i]=0;
    	rep(i,lim2,nown-1)b[i]=0;
    	fntt(a,1),fntt(b,1);
    	rep(i,0,nown-1)a[i]=(LL)a[i]*(LL)b[i]%mod;
    	fntt(a,-1);
    	rep(i,0,lim1-1)v[L][i]=a[i];int lim3=min(k,lim1+lim2-1);
    	rep(i,lim1,lim3)v[L].push_back(a[i]);
    	return;
    }
    int main()
    {
    	t=read();po[0]=po[1]=1;
    	rep(i,1,152501)po[i]=(LL)po[i-1]*(LL)i%mod;inv[152501]=mul(po[152501],mod-2);
    	dwn(i,152500,1)inv[i]=(LL)inv[i+1]*(LL)(i+1)%mod;
    	while(t--)
    	{
    		n=read(),k=read();
    		reset();
    		rep(i,1,n)p[i]=read();
    		rep(i,1,n)if(!vis[i]){cnt++,siz[cnt]=getsiz(i);}
    		getans(1,cnt);int lim=v[1].size();
    		if(lim<=k)write(0);
    		else write((LL)v[1][k]*(LL)mul(C(n,k),mod-2)%mod);
    	}
        return 0;
    }
    

    t2

    题目大意

    有一个列数为(m)((mleq8))的方格图,有(s1)种颜色的(1*2)的地砖,(s2)种颜色的(2*1)的地砖,(f(x))表示当方格图行数为(x)时,将整个方格图铺满有多少种方案
    给出(L,R)((Lleq Rleq10^{2501})),求(f(L)+f(L+1)+...+f(R-1)+f(R))模998244353

    题解

    前置知识不会,先坑着

    代码

    只会80分矩乘

    #include<algorithm>
    #include<cmath>
    #include<complex>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define maxs ((1<<8)+3)
    #define maxlen 2510
    #define LL long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(int x)
    {
    	if(x==0){putchar('0'),putchar('
    ');return;}
    	int f=0;char ch[20];
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    	return;
    }
    const LL mod=998244353;
    int vis[maxs],sta[maxs],cnt,ans[2][maxs],to[maxs][maxs],tmpans[maxs],tmp[maxs][maxs],tmp2[maxs][maxs],tmp3[maxs][maxs];
    int num[2][maxlen],len[2],m,s1,s2;
    int mul(int x,int y)
    {
    	int ans=1;
    	while(y)
    	{
    		if(y&1)ans=(LL)ans*(LL)x%mod;
    		x=(LL)x*(LL)x%mod,y>>=1;
    	}
    	return ans;
    }
    void getst(int id,int step,int nowst,int cnt1,int cnt2)
    {
    	if(step==m)
    	{
    		if(!vis[nowst])vis[nowst]=++cnt,sta[cnt]=nowst;
    		to[id][vis[nowst]]=(to[id][vis[nowst]]+(LL)mul(s1,cnt1)%mod*(LL)mul(s2,cnt2)%mod)%mod;return;
    	}
    	if((sta[id]&(1<<step))!=0)getst(id,step+1,nowst,cnt1+1,cnt2);
    	else
    	{
    		if(step<m-1&&((sta[id]&(1<<step))==0)&&((sta[id]&(1<<(step+1)))==0))getst(id,step+2,nowst,cnt1,cnt2+1);
    		getst(id,step+1,(nowst|(1<<step)),cnt1,cnt2);
    	}
    	return;
    }
    void work(int f)
    {
    	rep(i,1,len[f])
    	{
    		rep(xi,1,cnt)rep(xj,1,cnt){tmp2[xi][xj]=0;if(xi==xj)tmp2[xi][xj]=1;}
    		int cntnum=0;
    		rep(j,1,num[f][i])
    		{
    			cntnum++;
    			rep(xi,1,cnt)
    				rep(xj,1,cnt)
    				{
    					tmp3[xi][xj]=0;
    					rep(xk,1,cnt)tmp3[xi][xj]=(tmp3[xi][xj]+(LL)tmp2[xi][xk]*(LL)tmp[xk][xj]%mod)%mod;
    				}
    			rep(xi,1,cnt)
    				rep(xj,1,cnt)
    					tmp2[xi][xj]=tmp3[xi][xj]; 
    		}
    		rep(xj,1,cnt)
    		{
    			tmpans[xj]=0;
    			rep(xk,1,cnt)tmpans[xj]=(tmpans[xj]+(LL)ans[f][xk]*(LL)tmp2[xk][xj]%mod)%mod;
    		}
    		rep(xi,1,cnt)ans[f][xi]=tmpans[xi];
    		rep(j,num[f][i]+1,10)
    		{
    			rep(xi,1,cnt)
    				rep(xj,1,cnt)
    				{
    					tmp3[xi][xj]=0;
    					rep(xk,1,cnt)tmp3[xi][xj]=(tmp3[xi][xj]+(LL)tmp2[xi][xk]*(LL)tmp[xk][xj]%mod)%mod;
    				}
    			rep(xi,1,cnt)
    				rep(xj,1,cnt)
    					tmp2[xi][xj]=tmp3[xi][xj]; 
    		}
    		rep(xi,1,cnt)rep(xj,1,cnt)tmp[xi][xj]=tmp2[xi][xj];
    	}
    	return;
    }
    int main()
    {
    	char c=getchar();
    	while(isdigit(c)){num[0][++len[0]]=c-'0',c=getchar();}
    	reverse(num[0]+1,num[0]+len[0]+1);
    	for(int i=1;i<=len[0];i++)
    		if(num[0][i]==0)num[0][i]=9;
    		else {num[0][i]--;break;}
    	while(!isdigit(c))c=getchar();
    	while(isdigit(c)){num[1][++len[1]]=c-'0',c=getchar();}
    	reverse(num[1]+1,num[1]+len[1]+1);
    	m=read(),s1=read(),s2=read();
    	vis[0]=1,sta[++cnt]=0;
    	rep(i,1,cnt)getst(i,0,0,0,0);cnt++;
    	rep(i,1,cnt-1)to[i][cnt]=to[i][1];
    	to[cnt][cnt]=1;
    	ans[0][1]=ans[1][1]=1;
    	rep(i,1,cnt)rep(j,1,cnt)tmp[i][j]=to[i][j];
    	work(0);
    	rep(i,1,cnt)rep(j,1,cnt)tmp[i][j]=to[i][j];
    	work(1);	
    	write(((ans[1][cnt]-ans[0][cnt])%mod+mod)%mod);
    	return 0;
    }
    

    t3

    题目大意

    有一棵有(n)((nleq152501))节点的树,有边权、点权,共有(q)((qleq152501))次操作,支持两种操作:
    1.修改一个点的点权
    2.给出两点(x,y),要在(x,y)之间的简单路径上找一个点(u),使得(x,y)之间的简单路径上其他点的点权乘该点到点(u)的距离之和最小,输出最小值
    保证2操作的结果不超过(10^{18})

    题解

    先坑着

    代码

    #include<algorithm>
    #include<cmath>
    #include<complex>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register int i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
    #define maxn 152510
    #define LL long long
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)&&ch!='-')ch=getchar();
    	if(ch=='-')f=-1,ch=getchar();
    	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return x*f;
    }
    void write(LL x)
    {
    	if(x==0){putchar('0'),putchar('
    ');return;}
    	int f=0;char ch[20];
    	if(x<0)putchar('-'),x=-x;
    	while(x)ch[++f]=x%10+'0',x/=10;
    	while(f)putchar(ch[f--]);
    	putchar('
    ');
    	return;
    }
    int dfn[maxn],tim,siz[maxn],n,q;
    int fir[maxn],nxt[maxn<<1],v[maxn<<1],cnt,anc[maxn][20];
    LL w[maxn<<1],dep[maxn],dep0[maxn],s[2][maxn],a[maxn],ans;
    void ade(int u1,int v1,LL w1){v[cnt]=v1,w[cnt]=w1,nxt[cnt]=fir[u1],fir[u1]=cnt++;}
    int lt(int x){return x&(-x);}
    void add(int x,LL y,int f){for(;x<=n;x+=lt(x))s[f][x]+=y;return;}
    LL ask(int x,int f){LL y=0;for(;x;x-=lt(x))y+=s[f][x];return y;}
    void getanc(int u)
    {
    	dfn[u]=++tim;siz[u]=1;
    	rep(i,1,18)anc[u][i]=anc[anc[u][i-1]][i-1];
    	for(int k=fir[u];k!=-1;k=nxt[k])
    		if(v[k]!=anc[u][0])anc[v[k]][0]=u,dep0[v[k]]=dep0[u]+1,dep[v[k]]=dep[u]+w[k],getanc(v[k]),siz[u]+=siz[v[k]];
    	return;
    }
    int Lca(int x,int y)
    {
    	if(dep0[x]<dep0[y])swap(x,y);
    	dwn(i,18,0)if(anc[x][i]&&dep0[anc[x][i]]>=dep0[y])x=anc[x][i];
    	if(x==y)return x;
    	dwn(i,18,0)if(anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
    	return anc[x][0];
    }
    LL getdis(int x,int y,int lca,int u)
    {
    	LL lans=(ask(dfn[x],1)-ask(dfn[anc[u][0]],1))-dep[u]*(ask(dfn[x],0)-ask(dfn[anc[u][0]],0)),
    	rans=(dep[u]-dep[lca]-dep[lca])*(ask(dfn[y],0)-ask(dfn[lca],0))+ask(dfn[y],1)-ask(dfn[lca],1)+
    	dep[u]*(ask(dfn[u],0)-ask(dfn[anc[lca][0]],0))-(ask(dfn[u],1)-ask(dfn[anc[lca][0]],1)),
    	lsiz=ask(dfn[x],0)-ask(dfn[u],0),rsiz=ask(dfn[anc[u][0]],0)-ask(dfn[anc[lca][0]],0)+ask(dfn[y],0)-ask(dfn[lca],0);
    	ans=(ans==-1)?lans+rans:min(ans,lans+rans);
    	return lsiz-rsiz;
    }	
    void work(int x,int y,int lca)
    {
    	int tx=x;LL nowsiz=getdis(x,y,lca,x),nxtsiz;
    	dwn(i,18,0)
    	{
    		if(anc[tx][i]&&dep0[anc[tx][i]]>dep0[lca])
    		{
    			nxtsiz=getdis(x,y,lca,anc[tx][i]);
    			if(nxtsiz<=0)
    			{
    				tx=anc[tx][i];
    				nowsiz=nxtsiz;
    			}
    		}
    	}
    	if(tx!=lca)getdis(x,y,lca,anc[tx][0]);
    	return;
    }
    int main()
    {
    	n=read();
    	memset(fir,-1,sizeof(fir));
    	rep(i,1,n)a[i]=read();
    	rep(i,1,n-1){int x=read(),y=read(),z=read();ade(x,y,z),ade(y,x,z);}
    	getanc(1);
    	rep(i,1,n)add(dfn[i],a[i],0),add(dfn[i]+siz[i],-a[i],0),add(dfn[i],a[i]*dep[i],1),add(dfn[i]+siz[i],-a[i]*dep[i],1);
    	q=read();
    	while(q--)
    	{
    		int tp=read(),x=read(),y=read(),lca=Lca(x,y);
    		if(tp==1)
    		{
    			ans=-1;
    			work(x,y,lca),work(y,x,lca);
    			write(ans);
    		}
    		else
    		{
    			int ad=y-a[x];
    			add(dfn[x],ad,0),add(dfn[x]+siz[x],-ad,0),add(dfn[x],dep[x]*ad,1),add(dfn[x]+siz[x],-dep[x]*ad,1);
    			a[x]=y;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Mybatis之批量更新操作
    Spring Quartz *.QRTZ_LOCKS' doesn't exist
    分析NTFS文件系统得到特定文件的内容
    设计模式笔记——设计模式原则总结
    android自己定义ViewPager之——3D效果应用
    Android混淆代码
    百度地图 Android SDK
    NYOJ17,单调递增最长子序列
    令人纠结的两行代码
    XCode中在提示窗体中对已弃用的API接口画上红线
  • 原文地址:https://www.cnblogs.com/xzyf/p/10106477.html
Copyright © 2011-2022 走看看