日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

[YY题]HDOJ5288 OO’s Sequence

發布時間:2023/11/27 生活经验 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。