牛客練習賽28 D 隨風飄(dp 字串雜湊)

2021-08-28 18:36:19 字數 1665 閱讀 2686

能用字串雜湊解決的問題,千萬別用字尾陣列、字典樹什麼的了……

這題有很多個詢問,每次詢問是從n個中拿走k個字串,問拿走之後的答案。我們顯然不能把所有拿走的方案列舉一遍,所以考慮計算每乙個字串的貢獻。這裡我的貢獻指第i個字串與它前面的字串的貢獻。而這個貢獻就是計算當前串與前面所有串的lcp。這裡千萬不要看到lcp就去想字尾陣列,這裡是多個串的lcp,而不是乙個串的lcp,所以字尾陣列顯然是麻煩了。字典樹是乙個好的選擇,但是字串雜湊顯然更簡單。對於每個串不斷的把它所有字首的雜湊值記錄下來,然後每個串的貢獻,就可以看它字首出現的次數。

然後我們考慮dp。令dp[i][j]表示考慮前i個串,從中取走j個串的答案。那麼可以分為第i個串取走或者不被取走,有:

前面部分表示第i個串取走,後面部分表示第i個串不取走。不取走的話就是前面i-1個串取走j個的答案,加上第i個串對前面產生的貢獻。出現這種情況的次數是

所以說最後就是

#include#define ll long long

#define pb push_back

#define lb lower_bound

#define ub upper_bound

#define inf ((1ll<<31)-1)

#define pi 3.1415926535

#define sf(x) scanf("%d",&x)

#include#include#include#include#define sc(x,y,z) scanf("%d%d%d",&x,&y,&z)

#define clr(x,n) memset(x,0,sizeof(x[0])*(n+5))

#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)

using namespace std;

using namespace __gnu_pbds;

const int n = 4010;

const int mod1 = 100001651;

const int mod2 = 100001623;

const int mod = 1000000007;

ll dp[n][310],c[n][n],f[n];

gp_hash_tablet;

char s[3000010];

int n,q;

ll add(ll pre1,ll pre2,int cur)

int main()

}for(int i=0;i<=n;i++) c[i][0]=1;

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

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

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

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

for(int j=0;j<=min(i,300);j++)

}while(q--)

return 0;

}

《牛客練習賽28 B》

這題主要就是多了乙個平方和的操作。我們維護平方和的值的時候。需要注意在下放的時候,要先把乘法之後的sum1算出來,這對算sum1最終的值沒有影響。但是對sum2的值有影響。因為我們在計算中就在更新adtag的值,所以這個adtag它的sum1應該最終化。includeusing namespace ...

牛客練習賽58 D 迷宮 dp

考慮到無論往左走還是往下走,下一步又會回來,進而不斷在兩個格仔間來回跳,所以只能往右走或者往下走,並且優先往右走 設 f i j 表示走到 i,j 的最小操作次數,考慮轉移 begin f i j to f i j 1 f i j s i j 1 0 to f i 1 j end 暴力轉移即可 我個...

牛客練習賽24 D

名字挺有意思的,排插樹,雖然這是個圖。算dijkstra的模版題,求最短路裡面最長的那條,因為到講台的距離總是取決於最短的那條路,但是又要求離講台最遠,那麼我們通過dijkstra計算出起始點到所有點的最短路然後遍歷找最大值就好。如下 include using namespace std type...