【题解】2021牛客OI赛前集训营-提高组(第三场)C. 打拳

需要一些脑洞。

充分体现了本蒟蒻 dp 菜的本质。

考虑 k=1 的情况。这种情况等价于,从 叶子结点 1 到根节点的所有祖先都被收买,且满足祖先节点都是子树的最大值。

那么我们考虑设 dp[i][j] 表示处理了前 i 个被收买的人,其中 j\in [0,2^n) 表示每个位置上的数是否被选择。转移时就找到一个不为 1 的位置,假设为 k,那么乘上一个组合数 ( b e a t [ i ] − c n t [ j ] − 2 2 k − 1 ) \binom{beat[i]-cnt[j]-2}{2^k-1} (2k1beat[i]cnt[j]2) 以及 beat[i] 子树内部的顺序 ( 2 k ) ! (2^k)! (2k)!

最后我们要注意到其实 1的位置并没有固定 ,所以要乘上 2 n 2^{n} 2n

时间复杂度 o ( 2 n n m ) o(2^nnm) o(2nnm) ,期望得分 50pts 。(能做到这一步已经很优秀了 qwq)

代码量不大。但是很有效。

#include<bits/stdc++.h> #define ll long long using namespace std; const int N=120000; //solution 65 pts : 打拳 int mod; int beat[N]; int n,m,k; ll C[550][550]; ll fact[550]; void init2() { fact[0]=1; for(int i=1;i<=530;i++) fact[i]=fact[i-1]*i%mod; for(int i=0;i<=530;i++) C[i][0]=1; for(int i=1;i<=530;i++) { for(int j=1;j<=i;j++) { C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; } } return; } void add(ll &x,ll y) { x=(x+y)%mod; } ll dp[17][N]; ll fpow(ll x,ll y) { ll mul(1); for(;y;y>>=1) { if(y&1) mul=mul*x%mod; x=x*x%mod; } return mul; } void work() { dp[0][0]=1; for(int i=0;i<m;i++) { for(int j=0;j<1<<n;j++) { if(dp[i][j]) { add(dp[i+1][j],dp[i][j]); for(int k=0;k<n;k++) { if((((j>>k)&1)==0)&&beat[i]>=(j+(1<<k)+1)) { add(dp[i+1][j+(1<<k)],dp[i][j]*C[beat[i]-j-2][(1<<k)-1]%mod*fact[1<<k]); } } } } } long long ans=dp[m][(1<<n)-1]; ans=ans*fpow(2,n)%mod; cout<<ans<<endl; } int main() { cin>>n>>m>>k>>mod; for(int i=0;i<m;i++) cin>>beat[i]; sort(beat,beat+m); init2(); work(); return 0; }

为了得到 100pts ,我们还需要对 LIS 进行转移 (其实这里思维难度不大,就是比较繁琐)

考虑怎么求一个序列的 LCS (我们重新定义求法)

从小到大考虑,每个位置的 LCS = i 前面 LCS 的最大值 + 1

这样我们考虑到序列长度还是 n ,总状态数只有区区 120000

所以时间复杂度为 o ( 120000 n m ) o(120000nm) o(120000nm) 可以通过。实际实现时要先写一个 dfs 把所有合法状态搜出来方便转移。

代码参见 std 。

#include<bits/stdc++.h> #define ll long long using namespace std; const int N=120000; //solution 100 pts : 打拳 int mod; int beat[105]; string s; map<string,int> vis; vector<string> ans; int tot=0; int n,m,k; void dfs(string s,int len) { if(vis[s]==0) { vis[s]=1; ans.push_back(s); tot++; } else return; if(len==n) return; for(int i=0;i<n;i++) { if(s[i]=='0') { string t=s; char c='0'; for(int j=0;j<i;j++) { c=max(c,s[j]); } t[i]=c+1; dfs(t,len+1); } } return; } string S[N]; map<string,int> ID; int num=0; ll cnt[N]; void init() { for(int i=0;i<tot;i++) { s=ans[i]; char c='0'; for(int j=0;j<n;j++) { if(s[j]=='0') { s[j]=c+1; c++; } else { c=max(c,s[j]); } } c='0'; for(int j=0;j<n;j++) c=max(c,s[j]); if(c>='0'+k) { S[++num]=ans[i]; ID[ans[i]]=num; } } for(int i=1;i<=num;i++) { for(int j=0;j<n;j++) { if(S[i][j]!='0') { cnt[i]|=1<<j; } } } return; } ll C[550][550]; ll fact[550]; void init2() { fact[0]=1; for(int i=1;i<=530;i++) fact[i]=fact[i-1]*i%mod; for(int i=0;i<=530;i++) C[i][0]=1; for(int i=1;i<=530;i++) { for(int j=1;j<=i;j++) { C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; } } return; } void add(ll &x,ll y) { x=(x+y)%mod; } ll dp[17][N]; string now,nxt; void modify(string &s,int pos) { char c='0'; for(int i=0;i<pos;i++) c=max(c,s[i]); s[pos]=c+1; } ll fpow(ll x,ll y) { ll mul(1); for(;y;y>>=1) { if(y&1) mul=mul*x%mod; x=x*x%mod; } return mul; } //核心代码这么短 ?? void work() { dp[0][1]=1; for(int i=0;i<m;i++) { for(int j=1;j<=num;j++) { if(dp[i][j]) { add(dp[i+1][j],dp[i][j]); now=S[j]; //考虑把第 i 个被收买的人放置到第 k 位 for(int k=0;k<n;k++) { if(now[k]=='0'&&beat[i]>=(cnt[j]+(1<<k)+1)) { nxt=now; modify(nxt,k); add(dp[i+1][ID[nxt]],dp[i][j]*C[beat[i]-cnt[j]-2][(1<<k)-1]%mod*fact[1<<k]); } } } } } long long ans=0; for(int j=1;j<=num;j++) { if(cnt[j]==(1<<n)-1) { add(ans,dp[m][j]); } } ans=ans*fpow(2,n)%mod; cout<<ans<<endl; } int main() { cin>>n>>m>>k>>mod; for(int i=0;i<m;i++) cin>>beat[i]; sort(beat,beat+m); for(int i=1;i<=n;i++) s=s+'0'; dfs(s,0); init(); init2(); work(); return 0; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530219.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(63)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示