zoukankan      html  css  js  c++  java
  • 【纪中集训2019.3.25】染色问题

    题目

    描述

    ​ 有一个纸片,纸片上有(n)个格子,初始时没有颜色;

    ​ 某个游戏的内容是进行(m)次染色,使得染完后(n)个格子一定有颜色;

    ​ 每次可以选择一个区间([l,r](l le r))去染(不能不染),颜色可以覆盖;

    ​ 问最后染出的序列有多少种;

    范围

    (n,m le 10^6) ;

    题解

    • 由于可以覆盖这个条件处理起来比较麻烦;

    • 考虑每次是插入一段颜色;

    • [egin{cases} &f_{i,j} = f_{i-1,j} + sum_{k=0}^{j-1} f_{i-1,k}(k+1) &(i lt m)\ &f_{i,j} = sum_{k=1}^{j-1} f_{i-1,k}(k+1) &(i = m) \ end{cases} ]

      • 插播一个我自己的十分没用的想法:

      • 只考虑管第一个转移,设 $ F_{i} $ 为 $ f_{i,j} $ 的 $ OGF $ 对比 $ f_{i,j}和f_{i,j-1} $ ,有:

      • [F_{i} = F_{i-1} + xF_i + x^2(F_{i-1})' ; \ F_{i} = frac{(x^2F_{i-1})'-F_{i-1}}{1-x} ;\ ]

      • 然后就没有然后了,。。。。。,TAT​;

    • 说正解:

    • 方程中存在两类贡献,一种是(f_{i,j} imes (j+1)),一种是(f_{i,j} imes 1);

    • 同时要求最后一次转移一定是第二种;

    • 枚举第一种转移的次数(k),求得贡献和后乘以((^{m-1}_{k-1}))

    • 考虑每次更新之后的形成的第一种转移次数的序列:(0 lt a_1 lt a_2 lt ,cdots, lt a_k = n)

    • 对于一种转移序列的贡献就是:((a_1+1)cdots(a_{k-1}+1)) ;

    • 这其实是([x^{n-k}]Pi_{i=1}^{n-1}(x+i+1)) ;

    • 所以答案是:(sum_{k=1}^{m} (^{m-1}_{k-1})[x^{n-k}]Pi_{i=1}^{n-1}(x+i+1));

    • 类似https://www.cnblogs.com/Paul-Guderian/p/10519990.html倍增可以(nlogn) ;

      #include<bits/stdc++.h>
      #define ll long long 
      #define mod 998244353
      #define il inline 
      using namespace std;
      const int N=4000010;
      int n,m,fac[N],inv[N],len,L,rev[N],f[N],g[N],a[N],b[N];
      il int pw(int x,int y){
      	int re=1;
      	if(y<0)y+=mod-1; 
      	while(y){
      		if(y&1)re=(ll)re*x%mod;
      		y>>=1;x=(ll)x*x%mod;
      	}
      	return  re;
      }
      il void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
      const int G=3;
      il void ntt(int*A,int F){
      	for(int i=0;i<len;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
      	for(int i=1;i<len;i<<=1){
      		int wn=pw(G,F*(mod-1)/(i<<1));
      		for(int j=0;j<len;j+=i<<1){
      			int w=1;
      			for(int k=0;k<i;++k,w=(ll)w*wn%mod){
      				int x=A[j+k],y=(ll)w*A[j+k+i]%mod;
      				A[j+k]=(x+y)%mod,A[j+k+i]=(x-y+mod)%mod;
      			}
      		}
      	}
      	if(!~F){
      		int iv=pw(len,mod-2);
      		for(int i=0;i<len;++i)A[i]=(ll)A[i]*iv%mod;
      	}
      }
      void solve(int n){
      	if(n==1){f[0]=2;f[1]=1;return;}
      	if(n&1){
      		solve(n-1);
      		for(int i=n-1;~i;--i)inc(f[i+1],f[i]),f[i]=(ll)(n+1)*f[i]%mod;
      		return ;
      	}
      	solve(n>>=1);
      	for(len=1,L=0;len<(n+1)<<1;L++,len<<=1);
      	for(int i=0;i<=len;++i){
      		rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
      		a[i]=b[i]=g[i]=0;
      	}
      	for(int i=0,pwn=1;i<=n;++i,pwn=(ll)pwn*n%mod){
      		a[i]=(ll)f[n-i]*fac[n-i]%mod;
      		b[i]=(ll)pwn*inv[i]%mod;
      	}
      	ntt(a,1);ntt(b,1);
      	for(int i=0;i<len;++i)a[i]=(ll)a[i]*b[i]%mod;
      	ntt(a,-1);
      	for(int i=0;i<=n;++i)g[i]=(ll)inv[i]*a[n-i]%mod;
      	ntt(f,1);ntt(g,1);
      	for(int i=0;i<len;++i)f[i]=(ll)f[i]*g[i]%mod;
      	ntt(f,-1);
      }
      int C(int x,int y){return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;}
      int main(){
      	freopen("color.in","r",stdin);
      	freopen("color.out","w",stdout);
      	scanf("%d%d",&n,&m);
      	for(int i=fac[0]=inv[0]=1;i<=m||i<=n;++i){
      		fac[i]=(ll)fac[i-1]*i%mod;
      		inv[i]=pw(fac[i],mod-2);
      	}
      	solve(n-1);
      	int ans=0;
      	for(int i=1;i<=n&&i<=m;++i){
      		int tmp=(ll)f[n-i]*C(m-1,i-1)%mod;
      		inc(ans,tmp);
      	}
      	cout<<ans<<endl;
      	return 0;
      }
      
  • 相关阅读:
    tensorflow笔记1_入门案例
    keras_非线性回归
    python_神经网络识别手写数字0-9
    python_天气查询小程序_1
    打开网站URL遇到“HTTP Error 418:”问题
    笔记1-1三层交换机实现vlan间路由
    用python写一个简单的BP神经网络
    linux系统定时检查网络状态python脚本
    文件名过长,无法删除。
    du 和 df命令
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/10638464.html
Copyright © 2011-2022 走看看