日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[HEOI2013] SAO(dp + 组合数 + 前缀和)

發(fā)布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [HEOI2013] SAO(dp + 组合数 + 前缀和) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

problem

luogu-P4099

solution

兩篇前提題解:排列計(jì)數(shù),老C的鍵盤

想必已經(jīng)看了 CQOI2017 老C的鍵盤 一題題解了。

這里直接考慮優(yōu)化狀態(tài)轉(zhuǎn)移方程。

我們發(fā)現(xiàn) f(u,i),f(v,j)f(u,i),f(v,j)f(u,i),f(v,j),當(dāng)枚舉 jjj 后,對應(yīng)的 kkk 是一段連續(xù)區(qū)間。

f(u,i)?f(v,j)?(k?1i?1)?(sizu+sizv?ksizu?i)f(u,i)*f(v,j)*\binom{k-1}{i-1}*\binom{siz_u+siz_v-k}{siz_u-i}f(u,i)?f(v,j)?(i?1k?1?)?(sizu??isizu?+sizv??k?) 轉(zhuǎn)移貢獻(xiàn)變化的只有 kkk,且有兩項(xiàng)都與之掛鉤。

我們不妨反過來固定 kkk,能轉(zhuǎn)移到這個 kkk 的肯定也是一段連續(xù)的 jjj

所以我們求出來 f(v,j)f(v,j)f(v,j) 后,直接做個前綴和,f(v,j)=∑j′≤jf(v,j′)f(v,j)=\sum_{j'\le j}f(v,j')f(v,j)=jj?f(v,j)

以要求 hu<hvh_u<h_vhu?<hv? 為例。

其原來是 i+j≤k≤i+sizvi+j\le k\le i+siz_vi+jki+sizv?,固定 i,ki,ki,k 后,能轉(zhuǎn)移過來的 jjj 范圍則為 1~k?i1\sim k-i1k?i

另一種則是 k?i<j≤sizvk-i<j\le siz_vk?i<jsizv?

兩種的 kkk 范圍也稍稍不同。

具體可以看代碼實(shí)現(xiàn)。

code

#include <bits/stdc++.h> using namespace std; #define int long long #define mod 1000000007 #define maxn 1005 char s[5]; int n; int c[maxn][maxn], f[maxn][maxn], g[maxn], siz[maxn]; vector < pair < int, int > > G[maxn];void dfs( int u, int fa ) {f[u][1] = siz[u] = 1;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i].first, w = G[u][i].second;if( v == fa ) continue;dfs( v, u );memcpy( g, f[u], sizeof( f[u] ) );memset( f[u], 0, sizeof( f[u] ) );for( int i = 1;i <= siz[u];i ++ )if( w ) {for( int k = i + 1;k <= i + siz[v];k ++ )(f[u][k] += f[v][k - i] % mod * g[i] % mod * c[k - 1][i - 1] % mod * c[siz[u] + siz[v] - k][siz[u] - i]) %= mod;}else {for( int k = i;k < i + siz[v];k ++ )(f[u][k] += (f[v][siz[v]] - f[v][k - i]) % mod * g[i] % mod * c[k - 1][i - 1] % mod * c[siz[u] + siz[v] - k][siz[u] - i]) %= mod;}siz[u] += siz[v];}for( int i = 1;i <= siz[u];i ++ ) (f[u][i] += f[u][i - 1]) %= mod; }signed main() {for( int i = 0;i <= 1000;i ++ ) {c[i][0] = c[i][i] = 1;for( int j = 1;j < i;j ++ )c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;}int T;scanf( "%lld", &T );while( T -- ) {scanf( "%lld", &n );memset( f, 0, sizeof( f ) );for( int i = 0;i < n;i ++ ) G[i].clear();for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %s %lld", &u, s, &v );G[u].push_back( make_pair( v, s[0] == '<' ) );G[v].push_back( make_pair( u, s[0] == '>' ) );}dfs( 0, 0 );printf( "%lld\n", ( f[0][n] + mod ) % mod );}return 0; }

總結(jié)

以上是生活随笔為你收集整理的[HEOI2013] SAO(dp + 组合数 + 前缀和)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。