C - Multiplicity CodeForces - 1061C(因子篩+線性dp)
Multiplicity
CodeForces - 1061C
Time limit 3000 ms Memory limit 262144 kB
Problem Description
You are given an integer array a1,a2,…,an.
The array bb is called to be a subsequence of aa if it is possible to remove some elements from aa to get b.
Array b1,b2,…,bk is called to be good if it is not empty and for every
Find the number of good subsequences in aa modulo 10^9+7.
Two subsequences are considered different if index sets of numbers included in them are different. That is, the values ?of the elements ?do not matter in the comparison of subsequences. In particular, the array
Input
The first line contains an integer n (1≤n≤100000) — the length of the array aa.
The next line contains integers a1,a2,…,an (1≤ai≤10^6).
Output
Print exactly one integer — the number of good subsequences taken modulo
Examples
Input2Output
1 2
3Input
5Output
2 2 1 22 14
13
Note
In the first example, all three non-empty possible subsequences are good: {1}{1}, {1,2}{1,2}, {2}{2}
In the second example, the possible good subsequences are: {2}{2}, {2,2}{2,2}, {2,22}{2,22}, {2,14}{2,14}, {2}{2}, {2,22}{2,22}, {2,14}{2,14}, {1}{1}, {1,22}{1,22}, {1,14}{1,14}, {22}{22}, {22,14}{22,14}, {14}{14}.
Note, that some subsequences are listed more than once, since they occur in the original array multiple times.
Solution:
首先看到這個mod 1e9+7,就勾起我不好的回憶了,費馬小定理(大質數),NNT(原根),dp(線性/背包/樹形/區間),矩陣快速冪
然後數據範圍 10w,應該是設計個O(n)的算法吧(感覺自己已經邊得很玄學了=_=!??)
想想可能是個線性dp。
先分析下題意吧,要組成一個子序列(相對位置保持不變,可以增刪一些元素),且第i個元素a[i]可以整除i,換句話說i是a[i]的因子
然後觀察下答案構成,假設有一個數X,那它僅能出現在 第因子位。
考慮dp,對於每個數依次取出,如果對答案有貢獻的話,肯定回添加進答案序列的某個結尾,這個結尾肯定是因子位,也就是說它會跟因子位的前一位的數組成全新的序列(因為自己的位置是全新的位置,肯定不會跟前面的沖突,互斥直接相加),既然如此,每個數間對答案貢獻即可疊加。
前i個數,因子是j(第j位),dp[i][j]=dp[i-1][j-1]( j是da[i]的因子),由於一個數會有多個因子,因子間不能沖突(只能在前面的數上累加嘛),所以要從右到左更新一個a[i]的貢獻
註意下 dp[0][0]=1,都是從這裏轉移出來的,方向向左,一直統計ans就行咯
最後統計因子需要用類似素數篩的方法,n*log n 復雜度統計所有的數的因子
#include <cstdio> #include <algorithm> #include <vector> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; ll dp[1000010],ans=0; ll n; vector<int>vf[1000010]; void init() { for (int i = 1; i <= 1000000; ++i) { for (int j = i; j <= 1000000; j += i) { vf[j].push_back(i); } } } ll cal(ll x) { ll tmp = 0; for (int i = vf[x].size()-1, now; i >=0; --i) { now = vf[x][i]; ans=(ans+dp[now-1])%mod; dp[now] = (dp[now - 1] + dp[now]) % mod; } return tmp; } int main() { scanf("%lld", &n); init(); ll x; dp[0] = 1; for (ll i = 1; i <= n; ++i) scanf("%lld", &x),cal(x); printf("%lld\n", ans); return 0; }
C - Multiplicity CodeForces - 1061C(因子篩+線性dp)