牛客 多校賽一

2021-08-21 17:26:26 字數 3354 閱讀 7907

lgv演算法

抄一波 牛客的解釋 (wiki 沒耐心看了)

lgv 演算法 (lindström–gessel–viennot lemma)

求以上矩陣的行列式,其中 e(a,b) 是從a到b的方法數,帶入求行列式即可得到(a1,a2,...an) 到 (b1,b2,...bn) 的所有不相交路徑的種數

再看這道題,其實就是要找從(n,0)到(0,m)的兩條可重合的路徑。如何將模型轉移到不相交?

一條路往左下角移一格

a1,a2 ----- (n,0) (n-1,-1)

b1,b2------ (0,m) (-1,m-1)

e(a1,b1) = ....

ans=

b symmetric matrix

很有意思,從矩陣--關聯到鄰接矩陣(圖論)--dp

最終轉換得到的題意是:給你n個不同的點,問能組成多少不同的環

先考慮n個不同的球能組成多少不同的乙個環 即:環排列 (n-1)!

dp我是想不到的,那就走一遍吧:

dp[n] 為數量為n的情況下,有多少的環的情況

1.從n-1個點裡找出1個點 與新加的點組成乙個環

(n-1)dp[n-2] 

2.從n-1個點中找出k個點 ,與新加的那個點組成乙個環

c(n-1,k) dp[n-k-1]*(k-1)! 

死活推不出。。。這一數學題。

老姐推出的。不貼**了 就照著公式寫

f(n) = (n-1) *f(n-2) +sum ((n-1)!*f(k)/k!/2)

e大意:對於乙個長度為 n 的由(1-k)組成的序列,去掉m個字元的不同子串行有多少個?

由去掉m個字元組成子串行可以理解為只取(n-m)個字元組成的不同序列。

首先遇到的問題是什麼?

同乙個字串可以有多種取法,那麼如何篩除重複,就是這個問題的關鍵。

官方題解寫的很不錯。

用dp做

dp[i][j] 代表取第i個位置的數,且其中刪除了j個數的情況數

再去計算next[i][c] 代表第i個位置之後 第乙個為c的位置(不包括位置i,且若是沒有,統一為n+1)

那麼這樣一來狀態轉移方程就是什麼啊?

dp[next[i][c]] [ next[i][c]-i-1+j ] +=dp[i][j]

解釋一下(我自己都看了好久。。。人蠢就要多努力)

對於一串原序列與子串行:

例如 原 1 2 1 2 1 1 2 1

子 1    1 2            (dp[4][1] -----刪了位置2)

對於 子串行 1 1 2 它下乙個的取值有4種情況 恰好是pos 5~8,但是若是m=1(只刪除乙個)的話,pos 5,6,8就會多次記錄,所以不能從位置四一一轉移到 5 6 8,只能留乙個,留哪個?很顯然,留5,它是第乙個出現的「1」,它的末尾可以接更多的值,就像直播時的前輩說的那樣,這個有點貪心的感覺。

如何去重的呢?

看例子的位置 5 dp[5][0]=2 (11和21)怎麼得到的11和21呢?位置是35和45只考慮這個數之前的第乙個值。

之後看牛客別人的**,發現大多數人不是這樣做的,他們是如何處理的呢?

dp[i][j]代表前i個位置,刪j 個數的情況數(注意,這裡不強制要求第i個數必須取,所以答案直接就是dp[n][m])

轉移方程:

dp( i , j ) = dp( i-1, j) +dp ( i-1, j-1) //第i個數不取+第i個數取

顯然,這裡會有重複,我很好奇,他們是怎麼處理重複的?

if(pre[i]&&pre[i]+j-i>=0)

dp[i][j]=(dp[i][j]-dp[pre[i]-1][pre[i]+j-i]+mod)%mod;

額?這波操作有點秀啊,看不懂啊!!不過怎麼這麼熟悉呢

if(pre[i]&&i-pre[i]<=j)//如果位置i的前乙個位置的數存在,並且能刪那麼多數

dp[i][j]=(dp[i][j]-dp[pre[i]-1][pre[i]+j-i]+mod)%mod;

舉例子:

1 2 3 4 3 3 2 1

到pos 5 就有問題了 序列123 13 23就會有重複了 

假設在pos5前dp[i][j] 一直保持它原本的意義 那麼根據轉移式

dp[5][0] 沒重複,不用減

dp[5][1]沒重複,不用減

dp[5][2]重複出現了 且減去 dp[2][1]    (對應123)

dp[5][3]                      減去 dp[2][2]     (對應12,13 )

dp[5][4].......都減去乙個0(因為dp越界了)

好神奇啊 為什麼啊?

有什麼神奇的,就是字面意思嘛

首先要減去的這個dp值的位置肯定是pre[i]-1因為之後才確定是哪個3嘛

那j是多少呢pre[i]+j-i即 j  -( i-pre[i] )中間都不刪啊,(有中間的元素的話,就是乙個新序列了嘛)

還有一種做法

ans[len] 代表長度為len的序列種數

nxt[len][num]代表長度為len,之後數字為num的種數

那麼 ans[len] += ans[len]-1 - nxt[len][a[i]] 

dp[i][j] = ans[j-1]

//額 看不懂了,貼一下**之後消化吧

#include #include #include #include #include #define n 2000050

using namespace std;

typedef long long ll;

const int max=1e5+10;

long long dp[max][20];

const int mod= 1e9+7;

long long ans[max];

long long a[max];

int main()

for(int i=1;i<=n;i++)

ans[0]=1;

for(int i=1;i<=n;i++)

}ans[n-m]=(ans[n-m]+mod)%mod;

cout

牛客多校 Playing games FWT

給出 n n 個數a1 a2,an role presentation style position relative a1,a2,a na1,a2,a n,問最多選出多少個數使得這些數的異或和為0。n,ai 5 105 n,a i 5 105 震驚!老年退役選手居然開始寫題解了。這次回家本來也沒打...

2018牛客多校3

h diff prime pairs 1 3 1 5 1 7 1 11.2 3 2 5 2 7 2 11.3 3 3 5 3 7 3 11.4 3 4 5 4 7 4 11.打個素數表 用素數篩一遍 includeusing namespace std bool a 11111111 int zs ...

牛客多校 Ternary String (數論)

示例1輸入複製3 000012 22輸出複製3 9345 思路 1.如果遇到了 0,t 2.如果遇到了1,t t 2 2 因為之前經歷了t,那麼就會派生出來t個0,加上乙個1的時間 2 就是上式了 3.如果遇到了2,t 3 2 t 1 可以類似於2來想,經過了t後到了乙個2 會變成這樣 211010...