1. 程式人生 > >Codeforces Round #526 (Div. 2) E. The Fair Nut and Strings

Codeforces Round #526 (Div. 2) E. The Fair Nut and Strings

and open contest blank onclick 分享 兩個 多少 int

E. The Fair Nut and Strings

題目鏈接:https://codeforces.com/contest/1084/problem/E

題意:

輸入n,k,k代表一共有長度為n的多少個字符串。然後給出一個最小字符串s,最大字符串t,滿足對於所有的k個字符串有s<=S<=t。

最後求滿足條件的k個字符串(自己構造)的不同前綴數量的和。

題解:

這題很巧妙,設dp(i)表示長度為i的前綴的數量和,一開始有dp(1)=0。

後來隨著長度的增加,我們每次可以在最後加一個a或者b,所以轉移方程為dp(i)=2*dp(i-1)。

但是由於有最大最小字符串的限制,當si=b時,dp(i)會多加一個;當ti=a時,dp(i)也會多加一個。減去即可。

可以用歸納法來證明,假設當前循環到第i層,前綴長度i-1滿足限制條件。那麽si=b時,dp(i-1)中,只有一個後面加上a時,會小於s;對於ti=a也同理。(可以想一下,提示:共同前綴)

最後輸出求和min(dp(i),k)。(k個字符串任意長度的前綴最多也只有k個)

註意一下代碼的細節。

代碼如下:

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+5;
ll n,k;
char s[N],t[N];
ll dp[N];
int main(){ cin>>n>>k; scanf("%s%s",s,t); dp[0]=1; ll ans = 0; for(int i=1;i<=n;i++){ char sc = s[i-1],tc = t[i-1]; dp[i]=2ll*dp[i-1]; if(sc==b) dp[i]--; if(tc==a) dp[i]--; if(dp[i]>=k){ dp[i]=k; ans
+=(n-i)*k; break ; } } for(int i=1;i<=n;i++) if(dp[i]) ans+=dp[i]; printf("%I64d",ans); return 0; }
View Code

還有一種就是把字符串看為二進制的,那麽數量就為兩個二進制相減。

直接給代碼:

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 ;
char s[N],t[N];
ll n,k;
int main(){
    cin>>n>>k;
    scanf("%s %s",s,t);
    ll a=0,b=0;
    ll ans =0;
    for(int i=0;i<n;i++){
        ll now;
        a<<=1;b<<=1;
        if(s[i]==b) a++;
        if(t[i]==b) b++;
        now = b-a+1;
        if(now>=k){
            ans+=(n-i)*k;
            break ;
        }
        ans+=now;
    }
    printf("%I64d",ans);
    return 0;
}
View Code

Codeforces Round #526 (Div. 2) E. The Fair Nut and Strings