能用字串雜湊解決的問題,千萬別用字尾陣列、字典樹什麼的了……
這題有很多個詢問,每次詢問是從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...