贡献思想 + 数论 + 思维(例题 Problem J. Prime Game)
首先說一下貢獻的思想:
舉個例子:已知有n個數,從?,求?中所有質因數出現的個數。
假設當前數為??6, 7, 5, 5, 4, 9, 9, 1, 8, 12
- 首先寫出他每個數的質因數:
| 6 | 7 | 5 | 5 | 4 | 9 | 9 | 1 | 8 | 12 |
| 2,3 | 7 | 5 | 5 | 2 | 3 | 3 | 0 | 2 | 2,3 |
- 那么求任意區間質因數的個數,就可以轉化為求解每個數在任意區間所作的貢獻度。
| 序號 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| ai | 6 | 7 | 5 | 5 | 4 | 9 | 9 | 1 | 8 | 12 |
| 質因數 | 2,3 | 7 | 5 | 5 | 2 | 3 | 3 | 0 | 2 | 2,3 |
| 貢獻度 | (10) + (10) | 9 + 9 | 8 + 8 + 8 | 7 | 6 + 6 + 6 + 6 | 5 + 5 + 5 + 5 | 4 | 0 | 2+2+2+2 | 1 + (1 + 2) |
(求解貢獻度時要注意前面已經出現和計算過的數字不在計算,防止重復。如:質因數2的貢獻,在序號為1處出現質因數為2,此時他的貢獻度為:
? ? ? ? [1, 1] , [1, 2], [1, 3] , [1, 4], [1, 5], [1, 6], [1, 7], [1, 8], [1, 9],? [1, 10]
在序號為5處出現質因數2,此時他的貢獻度為:
? ? ? ? [1, 5](這個已經被計算過一次,舍去)
? ? ? ? ? ?實際貢獻度:[5, 5] , [5, 6] , [5, 7] , [5, 8] , [5, 9] , [5, 10]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[2, 5] , [2, 6] , [2, 7] , [2, 8] , [2, 9] , [2 , 10]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[3, 5] , [3, 6] ,?[3, 7] , [3, 8] , [3, 9] ,?[3, 10]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[4, 5] , [4, 6] , [4, 7] , [4, 8] , [4, 9] ,?[4, 10]
在序號為9處出現質因數2, 此時他的貢獻度為:
? ? ? ? ? 實際貢獻度: [9, 9] , [9, 10]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[6, 9] , [6, 10]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[7, 9] , [7, 10]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[8, 9] , [8, 10]
在序號為10處出現質因數2,此時他的貢獻度為:
? ? ? ? 實際貢獻度:? [10, 10]
)
好處:
如果直接使用暴力的算法的話,時間復雜度為,避免不了求區間的情況,但如果使用求貢獻度的思維去求,可以在O(n)的時間復雜度內完成
然后就是求解每個數的質因數分解:
可以直接用埃式篩法來得到:
const int maxn = 1e6+5; int vis[maxn]; vector<int>v[maxn]; void init(){memset(vis, 0, sizeof(vis));for(int i = 2; i < maxn; i++){if(!vis[i]){v[i].push_back(i);for(int j = 2*i; j < maxn; j += i){vis[j] = 1;v[j].push_back(i);}}} }然后就很好求解了。。。。。。。
?
一道例題:
?
這道題就是一道求貢獻度的題,只要理解上面就很好求解了:
#include<bits/stdc++.h>using namespace std; typedef long long LL;const int maxn = 1e6+5; int vis[maxn]; vector<int>v[maxn]; vector<int>pos[maxn]; int n; int a[maxn];void init(){memset(vis, 0, sizeof(vis));for(int i = 2; i < maxn; i++){if(!vis[i]){v[i].push_back(i);for(int j = 2*i; j < maxn; j += i){vis[j] = 1;v[j].push_back(i);}}} }int main() {init();scanf("%d", &n);for(int i = 1; i <= n; i++) scanf("%d", &a[i]);LL ans = 0;for(int i = 1; i <= n; i++){if(a[i] == 1) continue;int tmpnum = v[a[i]].size();for(int j = 0; j < tmpnum; j++){int now = v[a[i]][j];if(pos[now].size() == 0){ans += 1LL * (n - i + 1) * i;pos[now].push_back(i);}else{vector<int>::iterator it = pos[now].end(); it--;int tmppos = *it;ans += 1LL * (n - i + 1) * (i - tmppos);pos[now].push_back(i);}}}printf("%lld\n", ans);return 0; }?
總結
以上是生活随笔為你收集整理的贡献思想 + 数论 + 思维(例题 Problem J. Prime Game)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阶乘的分解质因数
- 下一篇: 关于数学里的一些知识