[YY题]HDOJ5288 OO’s Sequence
題意:求這個式子 $\sum \limits_{i=1}^{n} \sum \limits_{j=1}^{m} f(i, j) mod (10^9 + 7)$ 的值
就是對每個區間[i, j]枚舉區間中的每個數$a_i$到$a_j$, 判斷這個$a$是否對[i, j]這個區間內所有數取模都不等于0, 若是,則這個區間滿足條件
問有多少個滿足條件的區間
比如案例是這樣跑的
int ans=0;for(int i=1;i<=5;i++)for(int j=i;j<=5;j++){for(int k=i;k<=j;k++) // 注意要枚舉[i, j]中的每個數{bool flag=0;for(int l=i;l<=j;l++)if(k!=l && k%l==0)flag=1;if(!flag) // 對區間內所有數取模都不等于0 ans++;}}
?
跟省賽某題很像, 計算每個數a[i]對ans的貢獻
比如對于案例 1 2 3 4 5
1這個數字對于答案的貢獻是{1}, {1, 2}, {1, 2, 3}, {1, 2, 3, 4}, {1, 2, 3, 4, 5} 這5個區間
2 這個數字對于答案的貢獻是{2}, {2, 3}, {2, 3, 4}, {2, 3, 4, 5} 這4個區間 ? ( {1, 2}區間不滿足,因為2%1==0 )
... ...
來看4 這個數?
它往左取區間 {4}, {3, 4} 當取到2的時候, 發現4%2==0了,那么就不必再往左了(對于連續的區間, 再往左則必定會經過2,那么該區間就不合法了)
同理,可以想到往右取, 當找到一個數被它取模等于0, 那么就不必再往右了
好了,現在對于一個數a[i], 它左邊 到 不合法的數(被它取模等于0)為止 之間有x個數, 右邊到不合法的數為止 有y個數
那么a[i]這個數對答案的貢獻就是(x+1)*(y+1)
為什么呢?
因為是連續的區間, 所以這個區間的左端點可以取a[i]左邊0個數、1個數、2個數... ...x個數;右邊0個數、1個數、2個數... ...y個數
左邊有(x+1)種取法,右邊有(y+1)種, 相乘就是總取法數
那么我們只要找到離a[i]最近的一左一右兩個不合法數的位置$l$和$r$, 那么$(i-l)*(r-i)$ 就是a[i]的貢獻($i-l-1$就是上面所講的x)
之后只要遍歷每個a, 將每個a的貢獻累加起來即是最后答案。
?
那么現在問題就轉化成了如何求一個 離它最近的 能被它整除的數 的位置
?
我們是這樣做的:
開個數組將每個a[i]的倍數都記為i ?(比如 a[0]=2, 那么就將2、4、6... ...10000 都記下0號位置;a[x]=y, 就將y、2y、3y... ... 都記下x位置)
就跟篩因子一樣 ? (因為1比較特殊,會退化到$n^2$, 因此特殊處理) ? 復雜度為O(NlogN) ?(N為10000, 因為數最大為10000)
for(int i=0;i<n;i++){if(a[i]==1)one.push_back(i);elsefor(int j=a[i];j<=10000;j+=a[i])b[j].push_back(i);}
?
因為是按順序遍歷了a數組, 所以記下的位置(比如2 2 3 6 12 ?對于12記下的是0 1 2 3 4 )一定是遞增的
那么就可以二分來尋找離$i$最近的位置
?
p.s. lower_bound 找的是大于等于x的數位置
? ? ? upper_bound找的是大于x的數的位置
?
1 const LL mod=1e9+7; 2 int a[100005]; 3 vector<int> b[10005]; 4 vector<int> one; 5 int read() 6 { 7 char ch=' '; 8 int ans=0; 9 while(ch<'0' || ch>'9') 10 ch=getchar(); 11 while(ch<='9' && ch>='0') 12 { 13 ans=ans*10+ch-'0'; 14 ch=getchar(); 15 } 16 return ans; 17 } 18 19 int main() 20 { 21 // freopen("1001.in", "r", stdin); 22 // freopen("out.txt", "w", stdout); 23 int n; 24 while(~scanf("%d", &n)) 25 { 26 for(int i=0;i<n;i++)a[i]=read(); 27 // scanf("%d", &a[i]); 28 for(int i=0;i<=10000;i++) 29 { 30 b[i].clear(); 31 b[i].push_back(-1); 32 } 33 one.clear(); 34 one.push_back(-1); 35 for(int i=0;i<n;i++) 36 { 37 if(a[i]==1) 38 one.push_back(i); 39 else 40 for(int j=a[i];j<=10000;j+=a[i]) 41 b[j].push_back(i); 42 } 43 for(int i=0;i<=10000;i++) 44 b[i].push_back(n); 45 one.push_back(n); 46 LL ans=0; 47 for(int i=0;i<n;i++) 48 { 49 int p1=lower_bound(b[a[i]].begin(), b[a[i]].end(), i)-b[a[i]].begin()-1; 50 int p2=lower_bound(one.begin(), one.end(), i)-one.begin()-1; 51 int l=max(b[a[i]][p1], one[p2]); 52 p1=upper_bound(b[a[i]].begin(), b[a[i]].end(), i)-b[a[i]].begin(); 53 p2=upper_bound(one.begin(), one.end(), i)-one.begin(); 54 int r=min(b[a[i]][p1], one[p2]); 55 // printf("%d %d\n", l, r); 56 ans=(ans+((i-l)*(r-i))%mod)%mod; 57 } 58 printf("%I64d\n", ans%mod); 59 } 60 return 0; 61 }HDOJ 5288
?
轉載于:https://www.cnblogs.com/Empress/p/4665979.html
總結
以上是生活随笔為你收集整理的[YY题]HDOJ5288 OO’s Sequence的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一盒海参多少钱啊?
- 下一篇: H - Parity game-poj1