CF1671F

前言

有没有一种可能,就是说,出题人打着 dp 的名号,考你生成函数?

思路

我们称一个范围是 \([l,r]\) 的段是置换的,当且仅当其值域也恰遍取 \([l,r]\)

我们称一个置换段是本原的,当且仅当其不能由其余置换段简单拼接而成。

我们称一个本原段是平凡的,当且仅当其长度为 \(1\);反之,则是不平凡的。

有结论:

  • 值域为 \([l,r]\) 的置换段 \(a_{l\sim r}\) 与长度为 \(r-l+1\) 的排列 \(p_{1\sim r-l+1}\) 构成一一映射 \(p_k=a_{k+l-1}-l+1\),且保持逆序数、下降数不变
  • 任何一个长度为 \(l\) 的本原段其逆序数 \(k\ge l-1\)
  • 任何一个排列可以由若干本原段拼接而成,其中不平凡的段数量不会超过原排列的逆序数

证明显然,略去。

注意到本题 \(k,x\) 很小,我们不妨预处理暴力枚举所有排列,即枚举每一类置换段的形式,记录有非平凡本原性、长度\(l(l\le12)\)逆序数\(k(k\le11)\)下降数\(x(x\le11)\) 的排列数量 CNT[l][k][x]

这部分复杂度是 \(O(k!)\) 级别的,实际在 \(l=12\) 时要跑得巨慢,建议打表。(似乎可用多项式 \(\ln\) 来解决而不用暴力?)

记生成函数 \(F(z)=\sum_{a,b,c}(Cnt_{a,b,c}u^bt^c)z^a\)(注意这里认为 \(u,t\) 都是常数),则答案的生成函数为:

\[{1\over1-z-F} \]

答案为

\[\\ [z^nu^kt^x]{1\over1-z-F} \\=[z^nu^kt^x]\sum_a\sum_p\binom{a+p}pz^aF^p\quad({\tt 这步用组合意义解释更简单}) \\=\sum_a[z^{n-a}u^kt^x]\sum_p\binom{a+p}pF^p \\=\sum_a\sum_p\binom{n-a+p}p[z^au^kt^x]F^p \\\]

(其实用组合意义解释更简单,可以避免生成函数)

由于 \(k,x\) 的限制,暴力预处理 \(F^1,F^2,\dots,F^{11}\) 即可,于是 \(a\le22\) 也是显然的,从而这个柿子可以暴力求。

综上,本题解完。

Code

如果常数实现不优秀,可能要考虑加一个火车头。

注释里的代码用于 CNT[12][][] 的打表卡常。

#include <algorithm>
#include <stdio.h>
#include <vector>
typedef long long llt;
typedef unsigned uint;typedef unsigned long long ullt;
typedef bool bol;typedef char chr;typedef void voi;
typedef double dbl;
template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
template<typename T>T lowbit(T n){return n&-n;}
template<typename T>T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<typename T>T lcm(T a,T b){return(a!=0||b!=0)?a/gcd(a,b)*b:(T)0;}
template<typename T>T exgcd(T a,T b,T&x,T&y){if(b!=0){T ans=exgcd(b,a%b,y,x);y-=a/b*x;return ans;}else return y=0,x=1,a;}
template<typename T>T power(T base,T index,T mod)
{
    T ans=1%mod;
    while(index)
    {
        if(index&1)ans=ans*base%mod;
        base=base*base%mod,index>>=1;
    }
    return ans;
}
namespace ConstMod
{
    template<const ullt p>
    class mod_ullt
    {
        private:
            ullt v;
            inline ullt chg(ullt w){return(w<p)?w:w-p;}
            inline mod_ullt _chg(ullt w){mod_ullt ans;ans.v=(w<p)?w:w-p;return ans;}
        public:
            mod_ullt():v(0){}
            mod_ullt(ullt v):v(v%p){}
            bol empty(){return!v;}
            inline ullt val(){return v;}
            friend bol operator<(mod_ullt a,mod_ullt b){return a.v<b.v;}
            friend bol operator>(mod_ullt a,mod_ullt b){return a.v>b.v;}
            friend bol operator<=(mod_ullt a,mod_ullt b){return a.v<=b.v;}
            friend bol operator>=(mod_ullt a,mod_ullt b){return a.v>=b.v;}
            friend bol operator==(mod_ullt a,mod_ullt b){return a.v==b.v;}
            friend bol operator!=(mod_ullt a,mod_ullt b){return a.v!=b.v;}
            inline friend mod_ullt operator+(mod_ullt a,mod_ullt b){return a._chg(a.v+b.v);}
            inline friend mod_ullt operator-(mod_ullt a,mod_ullt b){return a._chg(a.v+a.chg(p-b.v));}
            inline friend mod_ullt operator*(mod_ullt a,mod_ullt b){return a.v*b.v;}
            friend mod_ullt operator/(mod_ullt a,mod_ullt b){return b._power(p-2)*a.v;}
            friend mod_ullt operator^(mod_ullt a,ullt b){return a._power(b);}
            inline mod_ullt operator-(){return _chg(p-v);}
            mod_ullt sqrt()
            {
                if(power(v,(p-1)>>1,p)!=1)return 0;
                mod_ullt b=1;do b++;while(b._power((p-1)>>1)==1);
                ullt t=p-1,s=0,k=1;while(!(t&1))s++,t>>=1;
                mod_ullt x=_power((t+1)>>1),e=_power(t);
                while(k<s)
                {
                    if(e._power(1llu<<(s-k-1))!=1)x*=b._power((1llu<<(k-1))*t);
                    e=_power(p-2)*x*x,k++;
                }
                return _min(x,-x),x;
            }
            mod_ullt inv(){return _power(p-2);}
            mod_ullt _power(ullt index){mod_ullt ans(1),w(v);while(index){if(index&1)ans*=w;w*=w,index>>=1;}return ans;}
            voi read(){v=0;chr c;do c=getchar();while(c>'9'||c<'0');do v=(c-'0'+v*10)%p,c=getchar();while(c>='0'&&c<='9');v%=p;}
            voi print()
            {
                static chr C[20];uint tp=0;
                ullt w=v;do C[tp++]=w%10+'0',w/=10;while(w);
                while(tp--)putchar(C[tp]);
            }
            voi println(){print(),putchar('\n');}
            mod_ullt operator++(int){mod_ullt ans=*this;return v=chg(v+1),ans;}
        public:
            inline ullt&operator()(){return v;}
            inline mod_ullt&operator+=(mod_ullt b){return*this=_chg(v+b.v);}
            inline mod_ullt&operator-=(mod_ullt b){return*this=_chg(v+chg(p-b.v));}
            inline mod_ullt&operator*=(mod_ullt b){return*this=v*b.v;}
            mod_ullt&operator^=(ullt b){return*this=_power(b);}
            mod_ullt&operator/=(mod_ullt b){return*this=b._power(p-2)*v;}
            mod_ullt&operator++(){return v=chg(v+1),*this;}
    };
}
const ullt Mod=998244353;
typedef ConstMod::mod_ullt<Mod>modint;
modint A[100005],B[100005];
modint CNT[13][12][12],User[12][27][12][12];
uint V[13],QAQ[13];
int main() // 总不会手写 ln 吧???
{
#ifdef MYEE
    freopen("QAQ.in","r",stdin);
#endif
	A[0]=1;for(uint i=1;i<=100000;i++)A[i]=A[i-1]*i;
	B[100000]=A[100000].inv();for(uint i=100000;i;i--)B[i-1]=B[i]*i;
	for(uint i=2;i<=11;i++)
	{
		for(uint j=0;j<i;j++)V[j]=j+1;
        V[i-1]=0;
		do
		{
            if(V[i-1]==i-1)continue;
            uint p=0;
            for(uint j=0;j<i;j++){_max(p,V[j]);if(p==j)break;}
            if(++p!=i)
            {
                for(uint j=p;j<i;j++)V[j]=i+p-1-j;
                continue;
            }
            for(uint j=0;j<i;j++)QAQ[j]=0;
			uint x=0,y=0;
			for(uint j=i-1;~j;j--)
            {
                for(uint k=V[j];k;k-=lowbit(k))x+=QAQ[k];
                for(uint k=V[j]+1;k<=i;k+=lowbit(k))QAQ[k]++;
            }
			for(uint j=1;j<i;j++)y+=V[j-1]>V[j];
			if(x<=11&&y<=11)CNT[i][x][y]++;
		}
		while(std::next_permutation(V,V+i));
        // puts("qwq");
	}
    // for(uint i=1;i<=11;i++)for(uint j=1;j<=11;j++)
        // CNT[12][i][j].print(),putchar(" \n"[j==11]);
    CNT[12][11][1]=11;CNT[12][11][2]=165;CNT[12][11][3]=462;CNT[12][11][4]=330;CNT[12][11][5]=55;CNT[12][11][6]=1;
    // for(uint i=1;i<=5;i++)for(uint j=1;j<=5;j++)for(uint k=1;k<=5;k++)
    //     CNT[i][j][k].print(),putchar(" \n"[k==5]);
	User[0][0][0][0]=1;
	for(uint p=1;p<=11;p++)for(uint i=1;i<=12;i++)for(uint j=1;j<=11;j++)for(uint k=1;k<=11;k++)
        for(uint q=24;q>=i;q--)for(uint u=11;u>=j;u--)for(uint v=11;v>=k;v--)
            User[p][q][u][v]+=User[p-1][q-i][u-j][v-k]*CNT[i][j][k];
    uint t;scanf("%u",&t);
    while(t--)
    {
    	uint n,k,t;
    	scanf("%u%u%u",&n,&k,&t);
    	auto binom=[&](uint n,uint k)->modint
    	{
    		if(n<k||n>Mod||k>Mod)return 0;
    		modint ans=B[k];
    		for(uint i=n-k+1;i<=n;i++)ans*=i;
    		return ans;
    	};
    	modint ans;
    	for(uint i=1;i<=22&&i<=n;i++)for(uint j=1;j<=11;j++)ans+=binom(n-i+j,j)*User[j][i][k][t];
	    ans.println();
    }
    return 0; 
}

再来放张表(可以通过在上面代码基础上修改得到):

CNT[2][1][1]=1;
CNT[3][2][1]=2;
CNT[3][3][2]=1;
CNT[4][3][1]=3;CNT[4][3][2]=1;
CNT[4][4][1]=1;CNT[4][4][2]=4;
CNT[4][5][2]=3;
CNT[4][6][3]=1;
CNT[5][4][1]=4;CNT[5][4][2]=4;
CNT[5][5][1]=2;CNT[5][5][2]=12;CNT[5][5][3]=2;
CNT[5][6][1]=2;CNT[5][6][2]=12;CNT[5][6][3]=4;
CNT[5][7][2]=9;CNT[5][7][3]=6;
CNT[5][8][2]=3;CNT[5][8][3]=6;
CNT[5][9][3]=4;
CNT[5][10][4]=1;
CNT[6][5][1]=5;CNT[6][5][2]=10;CNT[6][5][3]=1;
CNT[6][6][1]=3;CNT[6][6][2]=28;CNT[6][6][3]=13;
CNT[6][7][1]=4;CNT[6][7][2]=35;CNT[6][7][3]=29;CNT[6][7][4]=1;
CNT[6][8][1]=3;CNT[6][8][2]=35;CNT[6][8][3]=41;CNT[6][8][4]=4;
CNT[6][9][1]=1;CNT[6][9][2]=30;CNT[6][9][3]=44;CNT[6][9][4]=7;
CNT[6][10][2]=17;CNT[6][10][3]=45;CNT[6][10][4]=7;
CNT[6][11][2]=8;CNT[6][11][3]=30;CNT[6][11][4]=11;
CNT[7][6][1]=6;CNT[7][6][2]=20;CNT[7][6][3]=6;
CNT[7][7][1]=4;CNT[7][7][2]=55;CNT[7][7][3]=50;CNT[7][7][4]=3;
CNT[7][8][1]=6;CNT[7][8][2]=80;CNT[7][8][3]=118;CNT[7][8][4]=18;
CNT[7][9][1]=6;CNT[7][9][2]=95;CNT[7][9][3]=186;CNT[7][9][4]=48;
CNT[7][10][1]=6;CNT[7][10][2]=101;CNT[7][10][3]=230;CNT[7][10][4]=85;CNT[7][10][5]=2;
CNT[7][11][1]=2;CNT[7][11][2]=94;CNT[7][11][3]=260;CNT[7][11][4]=113;CNT[7][11][5]=4;
CNT[8][7][1]=7;CNT[8][7][2]=35;CNT[8][7][3]=21;CNT[8][7][4]=1;
CNT[8][8][1]=5;CNT[8][8][2]=96;CNT[8][8][3]=145;CNT[8][8][4]=26;
CNT[8][9][1]=8;CNT[8][9][2]=155;CNT[8][9][3]=358;CNT[8][9][4]=124;CNT[8][9][5]=3;
CNT[8][10][1]=9;CNT[8][10][2]=207;CNT[8][10][3]=616;CNT[8][10][4]=313;CNT[8][10][5]=16;
CNT[8][11][1]=11;CNT[8][11][2]=250;CNT[8][11][3]=859;CNT[8][11][4]=567;CNT[8][11][5]=53;
CNT[9][8][1]=8;CNT[9][8][2]=56;CNT[9][8][3]=56;CNT[9][8][4]=8;
CNT[9][9][1]=6;CNT[9][9][2]=154;CNT[9][9][3]=350;CNT[9][9][4]=126;CNT[9][9][5]=4;
CNT[9][10][1]=10;CNT[9][10][2]=268;CNT[9][10][3]=898;CNT[9][10][4]=552;CNT[9][10][5]=48;
CNT[9][11][1]=12;CNT[9][11][2]=389;CNT[9][11][3]=1654;CNT[9][11][4]=1404;CNT[9][11][5]=204;CNT[9][11][6]=1;
CNT[10][9][1]=9;CNT[10][9][2]=84;CNT[10][9][3]=126;CNT[10][9][4]=36;CNT[10][9][5]=1;
CNT[10][10][1]=7;CNT[10][10][2]=232;CNT[10][10][3]=742;CNT[10][10][4]=448;CNT[10][10][5]=43;
CNT[10][11][1]=12;CNT[10][11][2]=427;CNT[10][11][3]=1967;CNT[10][11][4]=1887;CNT[10][11][5]=357;CNT[10][11][6]=6;
CNT[11][10][1]=10;CNT[11][10][2]=120;CNT[11][10][3]=252;CNT[11][10][4]=120;CNT[11][10][5]=10;
CNT[11][11][1]=8;CNT[11][11][2]=333;CNT[11][11][3]=1428;CNT[11][11][4]=1302;CNT[11][11][5]=252;CNT[11][11][6]=5;
CNT[12][11][1]=11;CNT[12][11][2]=165;CNT[12][11][3]=462;CNT[12][11][4]=330;CNT[12][11][5]=55;CNT[12][11][6]=1;
posted @ 2022-07-13 13:06  myee  阅读(16)  评论(0编辑  收藏  举报