CF1152F

能学到很多的题。

如何构造一个序列?

朴素:按照下标一位一位构造。

特殊:按随机顺序依次在某个元素前后插入。

再特殊:从小到大插入。

这里因为限制是 aiai1+m,所以从小到大插入很有优势,因为每个数 x,仅能插入到 [xm,x1] 之后。

因为任意两个数不能相等,所以启发我们可以在值域上搞。

但显然我们还需要压值域 [im,i] 的状态,因为 i 能插的位置仅仅在这些位置之后或者开头。因为 aiai1+m,显然 min{ai1}=aim,又因为是值域上一个个做下去,所以 max{ai1}=i1,所以对于当前枚举的值域 [1,i],我们需要记录 [im,i] 的状态为 S

T=2m+11,因为压 [im,i] 总共 m+1 个数。

las=(S<<1)&T,值域向右平移一位嘛。

不填,判 S 最高位为 0。f[i][j][S]=f[i1][j][las]+f[i1][j][las|1]

填,判 S 最高位为 1。f[i][j][S]=(f[i1][j1][las]+f[i1][j1][las|1])(pop_count(las)+1)

#include <bits/stdc++.h> //#define int long long #define pb push_back using namespace std; const int mod=(int)(1e9+7),N=(int)(1e5+1); int f[N][13][(1ll<<5)],n,k,m; signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n>>k>>m; int T=(1<<(m+1))-1; //1 1 f[0][0][0]=1; for(int i=1;i<=n;i++) { for(int j=0;j<=k;j++) { for(int S=0;S<=T;S++) { bool fl=(S>>m)&1; if(fl&&!j) continue ; int las=(S<<1)&T; int qwq=__builtin_popcount(las)+1; if(!fl) f[i][j][S]=((f[i-1][j][las]+f[i-1][j][las|1])%mod+f[i][j][S])%mod; if(fl) f[i][j][S]=((1ll*f[i-1][j-1][las]*qwq%mod+1ll*f[i-1][j-1][(las|1)]*qwq%mod)%mod+f[i][j][S])%mod; // cout<<i<<" "<<j<<" "<<S<<" "<<las<<" "<<f[i][j][S]<<'\n'; } } } int ans=0; for(int S=0;S<=T;S++) { ans=(ans+f[n][k][S])%mod; } cout<<ans; return 0; }

F2 矩乘优化

https://www.cnblogs.com/xugangfan/p/16495212.html

#include <bits/stdc++.h> //#define int long long #define pb push_back using namespace std; const int mod=(int)(1e9+7),N=(int)(1e5+1); int n,k,m,tot,id[14][1<<4]; struct Mat { int a[230][230]; Mat() { memset(a,0,sizeof(a)); } void mul(Mat g) { Mat res; for(int i=1;i<=tot;i++) for(int j=1;j<=tot;j++) for(int k=1;k<=tot;k++) res.a[i][j]=(res.a[i][j]+1ll*a[i][k]*g.a[k][j]%mod)%mod; *this=res; } }ans,B; signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n>>k>>m; int T=(1<<m)-1; //1 1 int CH=(1<<(m-1)); // for(int i=0;i<n;i++) { // for(int j=0;j<=k;j++) { // for(int S=0;S<=T;S++) { // int NEX=(S>>1)&T; // int qwq=__builtin_popcount(S>>1)+1; // f[i+1][j+1][NEX|CH]=(f[i+1][j+1][NEX|CH]+1ll*f[i][j][S]*qwq%mod)%mod; // f[i+1][j][NEX]=(f[i+1][j][NEX]+f[i][j][S])%mod; // } //抽象成一条边,因为矩阵乘法每次多经过 1 条边,相乘->方案数 // } // } tot=0; for(int j=0;j<=k;j++) for(int S=0;S<=T;S++) id[j][S]=++tot; for(int j=0;j<=k;j++) { for(int S=0;S<=T;S++) { int NEX=(S>>1)&T,qwq=__builtin_popcount(S)+1; B.a[id[j][S]][id[j][NEX]]=(B.a[id[j][S]][id[j][NEX]]+1)%mod; if(j<k) B.a[id[j][S]][id[j+1][NEX|CH]]=(B.a[id[j][S]][id[j+1][NEX|CH]]+qwq)%mod; } } ans=B; --n; while(n) { if(n&1) ans.mul(B); n>>=1; B.mul(B); } int answ=0; for(int S=0;S<=T;S++) { answ=(answ+ans.a[id[0][0]][id[k][S]])%mod; } cout<<answ; return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/16494878.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示