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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

codeforces gym-101741 Subsequence Sum Queries 分治+离线

發(fā)布時(shí)間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 codeforces gym-101741 Subsequence Sum Queries 分治+离线 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目

這里寫(xiě)鏈接內(nèi)容

題意

給出一個(gè)最長(zhǎng)為200000200000數(shù)列
給出一堆最多為200000200000個(gè)詢問(wèn)區(qū)間,問(wèn)從這些區(qū)間中取出一些數(shù)使得數(shù)字之和是m的倍數(shù),有多少種方案。其中保證1m201≤m≤20。

題解

最容易想到的方法就是倍增+dp來(lái)做。
定義f[i][j][k]f[i][j][k]表示區(qū)間[l,l+2j)[l,l+2j)內(nèi),選取數(shù)字之和modm==kmodm==k的方案數(shù)。
這種dpdp很容易想到,轉(zhuǎn)移方程也比較容易寫(xiě),但是空間復(fù)雜度會(huì)爆炸掉,因此我們必須換一種方法。

離線分治算法:
對(duì)于最開(kāi)始的區(qū)間[1,n][1,n]我們考慮它的中點(diǎn)mid=(1+n)/2mid=(1+n)/2,有的詢問(wèn)區(qū)間包含了mid這個(gè)點(diǎn),有的在mid點(diǎn)左邊,有的在mid點(diǎn)右面。
在這里我們可以用O(n)O(n)的時(shí)間復(fù)雜度內(nèi)計(jì)算出所有包含mid點(diǎn)的詢問(wèn)區(qū)間的答案,然后把剩下的詢問(wèn)區(qū)間分到左右兩邊,然后再分治解決。

如何在O(n)O(n)的時(shí)間復(fù)雜度內(nèi)計(jì)算出所有包含mid點(diǎn)的詢問(wèn)區(qū)間的答案:
記錄f[i][k]f[i][k]表示區(qū)間[l,mid][l,mid]之間選取數(shù)字之和模m等于k的方案數(shù)。
記錄g[i][k]g[i][k]表示區(qū)間[mid+1,i][mid+1,i]之間選取數(shù)字之和模m等于k的方案數(shù)。
那么問(wèn)區(qū)[l,r](lmidr)m?10f[l][i]?g[r][(m?i)%m]詢問(wèn)區(qū)間[l,r](l≤mid≤r)的答案就是:∑0m?1f[l][i]?g[r][(m?i)%m]

代碼

#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <cstring> using namespace std; #define pr(x) cout<<#x<<":"<<x<<endl const int maxn = 2e5+7; int n,m,q; int query[maxn][3]; int g[maxn][22]; int f[maxn][22]; int a[maxn]; const int mod = 1e9+7; void solve(int l,int r,vector<int> qs){if(l >= r || qs.size() == 0)return ;int mid = (l + r) / 2;for(int i = l;i < r;++i) for(int j = 0;j < m;++j)g[i][j] = f[i][j] = 0;f[mid][0] = 1;for(int i = mid-1;i >= l;i--){for(int j = 0;j < m;++j){f[i][(j+a[i])%m] = (f[i][(j+a[i])%m] + (long long)f[i+1][j]) % mod;f[i][j] = (f[i][j] + f[i+1][j]) % mod;}}g[mid-1][0] = 1;for(int i = mid;i < r;++i){for(int j = 0;j < m;++j){g[i][j] = (g[i][j] + g[i-1][j]) % mod;g[i][(j+a[i])%m] = (g[i][(j+a[i])%m] + (long long)g[i-1][j]) % mod;}}vector<int> qs1,qs2;for(auto i : qs){if(query[i][1] < mid-1) qs1.push_back(i);else if(query[i][0] > mid) qs2.push_back(i);else {if(query[i][1] == mid-1){query[i][2] = f[query[i][0]][0];}else if(query[i][0] == mid){query[i][2] = g[query[i][1]][0];}else{for(int j = 0;j < m;++j){query[i][2] = (query[i][2] + (long long)f[query[i][0]][j] * g[query[i][1]][(m-j)%m])% mod;}}} }solve(l,mid,qs1);solve(mid,r,qs2); } int main(){scanf("%d%d",&n,&m);for(int i = 1;i <= n;++i){scanf("%d",&a[i]);a[i] %= m;}vector<int> qs;scanf("%d",&q);for(int i = 0; i < q;++i){scanf("%d %d",&query[i][0],&query[i][1]);qs.push_back(i);}solve(1,n+1,qs);for(int i = 0;i < q;++i){printf("%d\n",query[i][2]);}return 0; }

總結(jié)

以上是生活随笔為你收集整理的codeforces gym-101741 Subsequence Sum Queries 分治+离线的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。