3、18 貢獻法學習

yyyne發表於2024-06-19

貢獻法
計算每一個字元對答案的貢獻,然後進行地推求解即可;

題目:

https://www.acwing.com/problem/content/5157/

計算貢獻

1、當[變化]的物件存在兩個時 嘗試[固定]一者
可以發現 對於ρ(“TCG”,”GCA”)而言 三輪操作中的每輪操作是等價的 每輪(第一層迴圈左移)對結果的貢獻是一致的 因此只需要考慮一輪即可
即可以固定s 而只看t的變化

2、當不易思考整體變化時 對[單體]採用[貢獻法]思考
可以發現對於t中的每個元素 在左移0 ~ n - 1的全域性操作中 其實就是和s中的每一個字元匹配一次
因此若t中的某個字元為’A’ 那麼其對結果的貢獻即為s中含有的’A’的數量
因此為了使得結果最大 t中的元素因儘可能為s中個數最多的元素
————————————————————————————————————————————————————————————————————————————————————————————————
思路

3、問題即轉換為 找到s中個數最多的元素 讓t中的每個元素都賦值為該元素即可

當s中最多的元素個數為1個時 只能將所有t中的元素都賦值為該元素 答案為1^n
當s中最多的元素個數為2個時 t中的每個元素都有兩種選擇 任選其一均可 答案為2^n
當s中最多的元素個數為3個時 t中的每個元素都有三種選擇 任選其一均可 答案為3^n
當s中最多的元素個數為4個時 答案為4^n

//題目問的是在出現最多重複元素之和下的字串的數量;
#include<bits/stdc++.h>
const int N=100010;
const int MOD = 1e9+7; 
using namespace std;
int n;
char str[N];
int cnt[100];
int main()
{
    cin>> n;
    cin >>str;
    // ct 儲存最大元素的個數
    // mx 儲存最大元素的大小 
    int ct=1,mx=0;
    for (int i = 0; i < n; i ++ ){
        int t=++cnt[str[i]];
        if(t>mx){
            mx=t;
            ct=1;
        }
        else if(mx==t){
            ct++;
        }
    }
    // 貢獻法求出最大元素個數的n次方;
    // 具體見      3、思路轉換
    long long res=1;
    for (int i = 0; i < n; i ++ ){
        res=(long long )res*ct%MOD;
    }
    cout<< res;
}

題目二:

https://www.acwing.com/problem/content/description/2871/

首先求出左右兩邊不相等字元的位置,然後根據遞推公式:pre[i]*next[j]求出每一個字元的貢獻;
注意左右兩端無相等字元的情況
相似的分析過程如:

分為三種情況:
1.左右相鄰處都有H牛 pre*nest;(兩者相乘就是需要丟棄的照片個數)
2.當左邊沒有H牛時,只計算右邊有多少H nest-1;
3.右邊沒有H牛時,只計算左邊有多少H pre-1;
其中 pre 表示的是前面有多少H牛

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
char str[N];
int pre[N],next_1[N],h[26];
int t;
int main(){
    cin >> str+1;
    long long res=0;
    int len=strlen(str+1);
    for (int i=1;i<=len;i++){
        int t=str[i]-'a';
        pre[i]=h[t]-i-1;
        h[t]=i;
    }
    for(int i=0;i<26;i++){
            h[i]=len+1;
        }
    for (int i=len;i>=1;i--){
        int t=str[i]-'a';
        next_1[i]=i-h[t]-1;
        h[t]=i;
    }
    for (int i = 1; i <= len; i ++ ){
        
        res+=(long long)(pre[i]+1)*(next_1[i]+1);
    }
    cout << res;
}

相關文章