一.闲谈
这次比赛真惨,B题我的数据分块被卡了,只有75分qwq,C题打分块和线段树都被卡了,我好难啊。。。
然后,看了下D题,emmm算了下一题,一看E题,哇数论题,于是操起草稿纸开干了。。。
二.题解
题目叫你求长度为n的序列,且数列元素为[1,k]的整数,且同时存在严格上升和严格下降的两个位置的序列的个数。
我一开始打算直接正着做,发现很不好搞,于是,正难则反嘛。。。我们就反着做
Ans=所有方案数-不同时存在严格上升和严格下降的序列数
注意到,所有方案数就是,这个可以直接跑一遍卡速米
然后,我们就是要求后面那一节了。
我们发现,不同时存在严格上升和严格下降的序列一定满足:
对于
那么,我们只需要统计这两个就好了。
注意到,这两种方案中,其中一种的倒序一定满足另一种,所以我们只需要求出一种的方案数x,另一种的的方案数便一定也是x了,不过,当所有取相同值的时候,会同时满足两个序列,所以两种的方案数之和应再减k
现在就是如何求其中一种的方案了
一开始,我不想算了,直接打了一组表:
n k ans 2 1 1 C(2,2) 2 2 3 C(3,2) 2 3 6 C(4,2) 2 4 10 C(5,2) 3 1 1 C(3,3) 3 2 4 C(4,3) 3 3 10 C(5,3) 3 4 20 C(6,3) 4 1 1 C(4,4) 4 2 5 C(5,4) 4 3 15 C(6,4) 4 4 35 C(7,4)
经过观测发现,这不就是k维前缀和有规律的组合数嘛?
找下规律就会发现,方案数就等于C(n+k-1,n)=C(n+k-1,k-1)
我们来理解下公式的意义:
现在我们求的是有n个数满足这n个数都属于且严格不下降(或者严格不上升)的方案数
其实公式的意义就相当于,我们先挖n+k-1个空,再从这些空里面选出k-1个空作为“隔板”
开头到第一个隔板之间的空填1,第一个隔板到第二个隔板填2。。。第k-1个隔板和末尾之间填k
这样,我们就成功的获得了一个长度为n(剩余n个空填数),严格不下降(每个隔板段中填的数依次递增)的方案数。(由于两个隔板可能相邻,所以,也有些数其实没有空填,所以所有方案都包含在内)
现在我们来解题
首先我们转换成公式形式:
约分一下:
读题的范围:
所以,我们直接先O(n)预处理出再在每次询问时,暴力计算答案的分子,最后直接处理答案即可~
代码:
#include<bits/stdc++.h> using namespace std; const int mod=998244353,N=1e6+1; int n,k; int ni[N],sp[N]; inline int ksm(int x,int y){ int ans=1; while(y){ if(y&1){ ans=(1LL*ans*x)%mod; } x=(1LL*x*x)%mod; y>>=1; } return ans%mod; } int main(){ ni[1]=1,sp[0]=sp[1]=1; for(int i=2;i<N;++i){ ni[i]=(1LL*ni[mod%i]*(mod-mod/i))%mod; sp[i]=(1LL*sp[i-1]*ni[i])%mod; } int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&k); if(k==1){//特判1 puts("0"); continue; } int tot=ksm(k,n); tot=(tot+k)%mod; int kil; if(k==2){ kil=(n+1)%mod; }else{ long long X=k+(n-1),Y=n; kil=1; for(int i=Y+1;i<=X;++i){ kil=(1LL*kil*i)%mod; } kil=(1LL*kil*sp[k-1])%mod; } tot-=(kil*2)%mod; tot=(tot%mod+mod)%mod; printf("%d\n",tot); } return 0; }