NC17621 管道取珠(模型轉換+DP)

題目鏈接

題意:
1n2m有兩個管道,管道1有n個球,管道2有m個球
AB球有A和B兩種顏色
ABC(n+m,n)從A或B分別取球,可能有C(n+m,n)種方案
這些方案中可能有取出球序列相同的
kai假設總共有k種不同的球序列,a_i爲每種的方案數
i=1kai=C(n+m,n)那麼\sum_{i=1}^k a_i=C(n+m,n)
i=1kai2 mod 1024523求\sum_{i=1}^k a_i^2~mod ~1024523
題解:
n,m<=500n,m<=500
i=1kai求\sum_{i=1}^k a_i可以直接得出
i=1kai2但是要求求的結果是\sum_{i=1}^k a_i^2
(n+m)如果這道題(n+m)比較小,可以考慮二進制枚舉
nm對於每種進行平方求和,但是這裏n,m太大,肯定不夠用
所以我們就可以把問題轉化
kk一般對於k次方,你就可以把他轉化成k個人玩這個遊戲
2就比如這道題,是兩次方,所以轉化成2個人玩這個遊戲
然後求這兩個人序列相同的方案數
ai,bi第一個拿到這個序列的方案數是a_i,第二個人是b_i
aibi那麼兩個人同時拿到這個序列的方案數就是a_i*b_i
ai==bi對於這道題中,遊戲相同,初始相同,所以a_i==b_i

2所以現在需要考慮的就是2個人玩這個遊戲序列相同的方案數
dp這樣就很明顯了,應該是用dp來求
dp然後開始構建dp的模型
狀態應該就是兩個人各自從兩個管道拿的球序列相同的方案
dp[i][j][k][l]1i2jdp[i][j][k][l]表示第一個人從管道1拿i個,管道2拿j個
1k2l第二個人從管道1拿k個,管道2拿l個兩人序列相同的方案
DP但是四維DP不論時間空間都不允許
考慮一下降維,我們會發現,兩個人序列相同,拿的個數肯定一樣
i+j==k+ll所以i+j==k+l,那麼就可以去掉l這一維

然後考慮狀態轉移,由於是拿的個數
我們考慮的應該是往下一個狀態轉移
122如果第一個人管道1(管道2)的當前球和第二個人管道2的當前球一樣
那麼就可以讓這兩個人分別拿相同球,並得到當前狀態的貢獻
這樣就可以形成狀態轉移(詳細見下代碼)

然後可以看到,這個遞推永遠是往下一個狀態轉移
也就是球數增長的方向,不需要前一步的值
使這樣的話,對於最外層循環那一維,就可以使用滾動數組

dp[n][m][n]最後得到dp[n][m][n]即可

AC代碼

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1024523;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int n,m;
int dp[2][510][510];
string a,b;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    cin>>n>>m;
    cin>>a>>b;a='.'+a,b='.'+b;
    dp[0][0][0]=1;
    int cur=0;
    for(int i=0;i<=n;i++,cur^=1)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=n;k++){
                int l=i+j-k;
                int &x=dp[cur][j][k];
                if(l<0||l>m)continue;
                if(a[i+1]==a[k+1])dp[cur^1][j][k+1]=(dp[cur^1][j][k+1]+x)%mod;
                if(a[i+1]==b[l+1])dp[cur^1][j][k]=(dp[cur^1][j][k]+x)%mod;
                if(b[j+1]==a[k+1])dp[cur][j+1][k+1]=(dp[cur][j+1][k+1]+x)%mod;
                if(b[j+1]==b[l+1])dp[cur][j+1][k]=(dp[cur][j+1][k]+x)%mod;
                x=0;
            }
    cout<<dp[cur][m][n];
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章