[NOIP2021] 数列
废物着实是我,我确也是废物。
除了原题,我连联赛题做出来的可能都没有。
这就更废物了。
所以我直接废物躺了。
因为从来没有见过类似的 DP 题,考场上我只用 naive 的思路去想这个题。
结果回来一复盘,哦豁,这个状态怎么还能这样定,还有这状态的转移怎么这么怪。。。
回过头来一想,才发现自己考场上想的思路全都是按自己的做题经验想的,根本不可能想到这种转移。。。
背题家实锤。。。马上连题都不会背了。。。
技不如人,甘拜下风。欢声笑语打出 gg。
定义状态 $f(i,j,k,p)$ 表示考虑到 $v_i$,现在序列考虑到了第 $j$ 个位置,第 $i$ 位及之前的 1 的个数为 $k$,并且这一位将要向下一位转移 $p$ 个 1。
然后这个直接往外推就完了,假设我们选了 $t$ 个 $i$:
$$f(i,j,k,p)\cdot v_i^t\cdot \binom{n-j}{t}\rightarrow f(i+1,j+t,k+(t+p)\bmod 2,\lfloor\dfrac{t+p}{2}\rfloor)$$
显然这个方程想转化为一个 $f(i,j,k,p)$ 的表达式并不是很现实。
然而我考场上接近一半的时间都在思考这种转移方式。
然后初态就是 $f(0,0,0,0)=1$。
最后把答案统计起来需要再数一下最后进的二进制位数。。。
反正跑不满,写了个快速幂,其实和常数差不多吧。。。
时间复杂度 $O(n^3mk)$。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include<iostream> #include<cstdio> #define ll long long using namespace std;
const ll N=30,M=1e2,mo=998244353;
ll n,m,k_,ans;
ll c[N+5][N+5],f[2][N+5][N+5][N+5],v[M+5];
inline ll qpow(ll b,ll p) { ll res=1;while(p){if(p&1) res=res*b%mo;b=b*b%mo;p>>=1;}return res; }
inline void Init() { c[0][0]=1; for(ll i=1;i<=N;i++) { c[i][0]=1; for(ll j=1;j<=i;j++) { c[i][j]=(c[i-1][j-1]+c[i-1][j])%mo; } } }
inline ll Bitcnt(ll x) {ll cnt=0;for(;x;x-=x&-x,cnt++);return cnt;}
inline ll read() { ll ret=0,f=1;char ch=getchar(); while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();} while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();} return ret*f; }
inline void write(ll x) { static char buf[22];static ll len=-1; if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);} else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);} while(len>=0) putchar(buf[len--]); }
int main() {
Init();
n=read();m=read();k_=read();
for(ll i=0;i<=m;i++) v[i]=read();
f[0][0][0][0]=1; for(ll i=0;i<=m;i++) { for(ll j=0;j<=n;j++) { for(ll k=0;k<=k_;k++) { for(ll p=0;p<=(n>>1);p++) { for(ll t=0;t<=n-j;t++) { f[(i+1)&1][j+t][k+(t+p)%2][(t+p)/2]= (f[(i+1)&1][j+t][k+(t+p)%2][(t+p)/2] +f[i&1][j][k][p]*qpow(v[i],t)%mo*c[n-j][t]%mo)%mo; } } } } for(ll j=0;j<=n;j++) { for(ll k=0;k<=k_;k++) { for(ll p=0;p<=(n>>1);p++) { f[i&1][j][k][p]=0; } } } }
for(ll k=0;k<=n;k++) { for(ll p=0;p<=(n>>1);p++) { if(Bitcnt(p)+k<=k_) ans=(ans+f[(m+1)&1][n][k][p])%mo; } }
write(ans);
return 0; }
|