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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

[XSY] 智慧树(线性同余方程组,线段树/树状数组)

發(fā)布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [XSY] 智慧树(线性同余方程组,线段树/树状数组) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

智慧樹

  • 解決此題有兩個要點(diǎn):
  • 如何判斷一個線性同余方程組有沒有解
  • 如何統(tǒng)計(jì)合法子序列數(shù)目
    • 先看第2點(diǎn):
      若一個序列是合法的,則這個序列的所有子序列都是合法的
      考慮?1≤i≤n\forall 1\leq i\leq n?1in,求出以iii為左端點(diǎn)時,序列右端點(diǎn)最右能取到哪,記為nxt[i]nxt[i]nxt[i]
      若不考慮l,rl,rl,r的限制,所有合法子序列數(shù)=∑i=1n(nxt[i]?i+1)\sum_{i=1}^{n}(nxt[i]-i+1)i=1n?(nxt[i]?i+1)
    • 加入l,rl,rl,r的限制,相當(dāng)于限制了:
      1.序列左端點(diǎn)必須≥l\geq ll
      2.序列右端點(diǎn)必須≤r\leq rr
      兩個限制不好同時處理,我們考慮分開處理:
      -采用離線做法,把詢問按lll從大到小排序,對每個詢問,只考慮 序列左端點(diǎn)i≥i\geqi當(dāng)前的lll 的序列,這樣便可保證滿足第一個限制。
      -對于第二個限制,維護(hù)cnt[j]cnt[j]cnt[j]表示 jjj是多少個 當(dāng)前納入考慮的合法序列 的右端點(diǎn),則詢問(l,r)(l,r)(l,r)的答案為∑j=lrcnt[j]\sum_{j=l}^{r}cnt[j]j=lr?cnt[j]
      以上可以用線段樹/樹狀數(shù)組維護(hù)(樹狀數(shù)組的區(qū)間修改、區(qū)間查詢戳這里)。
    • 再看第1點(diǎn):
  • 樸素做法:
    既然不保證mim_imi?為質(zhì)數(shù),那么就不能用CRTCRTCRT,只能用exCRTexCRTexCRT
    考慮方程組:
    {x≡b1(modm1)x≡b2(modm2)\begin{cases}x\equiv b_1(\mod m_1) \\x\equiv b_2(\mod m_2)\end{cases}{xb1?(modm1?)xb2?(modm2?)?
    x=m1k1+b1=m2k2+b2x=m_1k_1+b_1=m_2k_2+b_2x=m1?k1?+b1?=m2?k2?+b2?
    ∴m1k1?m2k2=b2?b1\therefore m_1k_1-m_2k_2=b_2-b_1m1?k1??m2?k2?=b2??b1?
    由拓展歐幾里得知,k1,k2k_1,k_2k1?,k2?有解,當(dāng)且僅當(dāng)∣b2?b1∣=gcd(m1,m2)|b_2-b_1|=gcd(m_1,m_2)b2??b1?=gcd(m1?,m2?)
    k1,k2k_1,k_2k1?,k2?有解,我們可以得到一個同時符合兩條方程的xxx值,設(shè)為x′x'x
    那么兩個方程可以合并為一個新的方程:
    x≡x′(modlcm(m1,m2))x\equiv x'(\mod lcm(m_1,m_2))xx(modlcm(m1?,m2?))
    用新方程再去和其它方程合并即可(ps:合并方程求nxtnxtnxt的過程可以用ST表優(yōu)化)
  • 正解:
    當(dāng)MMM較大時,由于解的模數(shù)較大,不宜基于求解來維護(hù)線性同余方程組。事實(shí)上,“求解”浪費(fèi)了信息,我們只需要知道“是否有解”
    • 先考慮 mim_imi?均為素?cái)?shù) 的特殊情況:
      一個方程組無解,當(dāng)且僅當(dāng)方程組中存在兩個方程:
      x≡bi(modp)x\equiv b_i(\mod p)xbi?(modp)x≡bj(modp)x\equiv b_j(\mod p)xbj?(modp),且bi!=bjb_i!=b_jbi?!=bj?

      為求nxtnxtnxt,我們維護(hù)一個由線性同余方程構(gòu)成的隊(duì)列,支持入隊(duì)、出隊(duì)和查詢這些方程構(gòu)成的方程組加上一個新方程組是否有解。
      而判斷方程組有沒有解,我們只需對每個素?cái)?shù)ppp維護(hù) 目前限制xmodpx \mod pxmodp的余數(shù)是什么、對xmodpx \mod pxmodp的余數(shù)的限制有幾個 即可
    • 再考慮 mim_imi?為任意正整數(shù) 的情況:
      假設(shè)mi=∏j=1pjajm_i=\prod_{j=1}p_j^{a_j}mi?=j=1?pjaj??ppp表示素?cái)?shù)),
      則方程x≡bi(modmi)x\equiv b_i(\mod m_i)xbi?(modmi?)可以分解成:
      {x≡bi(modp1a1)x≡bi(modp2a2)x≡bi(modp3a3)...\begin{cases}x\equiv b_i(\mod p_1^{a_1}) \\x\equiv b_i(\mod p_2^{a_2})\\x\equiv b_i(\mod p_3^{a_3})\\...\end{cases}??????????xbi?(modp1a1??)xbi?(modp2a2??)xbi?(modp3a3??)...?
      那么一個方程組無解,當(dāng)且僅當(dāng)方程組中存在兩個方程:
      x≡bi(modpa)x\equiv b_i(\mod p^a)xbi?(modpa)x≡bj(modpa)x\equiv b_j(\mod p^a)xbj?(modpa),且bi!=bjb_i!=b_jbi?!=bj?

      做法類似上面,對每個pap^apa維護(hù) 目前限制xmodpax \mod p^axmodpa的余數(shù)是什么、對xmodpax \mod p^axmodpa的余數(shù)的限制有幾個 即可
    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N=1e6+10; int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f; } int pri[N],cnt,vis[N],mn[N]; int n,m[N],b[N],q; int lim[N],tot[N],nxt[N]; //nxt[i]記錄以i為區(qū)間左端點(diǎn),區(qū)間右端點(diǎn)最右能取到哪 struct Que{int l,r,id;friend bool operator < (Que a,Que b){return a.l<b.l;} }que[N]; ll ans[N]; void init(){vis[0]=vis[1]=1;for(int i=2;i<=1000000;i++){if(!vis[i]){pri[++cnt]=i;mn[i]=i;}for(int j=1;j<=cnt,pri[j]*i<=1000000;j++){vis[pri[j]*i]=1;mn[i*pri[j]]=pri[j];if(i%pri[j]==0) break;}} } void del(int i){int tmp=m[i];while(tmp!=1){int fac=mn[tmp],pw=1;while(tmp%fac==0){tmp/=fac;pw*=fac;}for(int k=pw;k>=1;k/=fac){tot[k]--;if(!tot[k]) lim[k]=-1;}} } void get_nxt(){memset(lim,-1,sizeof(lim));int j=n+1;for(int i=n;i>=1;i--){int tmp=m[i];while(tmp!=1){int fac=mn[tmp],pw=1;while(tmp%fac==0){tmp/=fac;pw*=fac;}for(int k=pw;k>=1;k/=fac){if(lim[k]!=-1&&lim[k]!=b[i]%k){while(lim[k]!=-1) del(--j);}}for(int k=pw;k>=1;k/=fac){tot[k]++;if(lim[k]==-1) lim[k]=b[i]%k;}}nxt[i]=j-1;//i最右能和j-1合并 }for(int i=n-1;i>=1;i--) nxt[i]=min(nxt[i],nxt[i+1]); } namespace SegmentTree{ll sum[N<<2],tag[N<<2];void pushdown(int u,int l,int r){if(tag[u]){int mid=(l+r)>>1;sum[u<<1]+=tag[u]*(mid-l+1);tag[u<<1]+=tag[u];sum[u<<1|1]+=tag[u]*(r-mid);tag[u<<1|1]+=tag[u];tag[u]=0;}}void add(int u,int l,int r,int a,int b,int x){if(a<=l&&r<=b){sum[u]+=x*(r-l+1);tag[u]+=x;return;}pushdown(u,l,r);int mid=(l+r)>>1;if(a<=mid) add(u<<1,l,mid,a,b,x);if(b>mid) add(u<<1|1,mid+1,r,a,b,x);sum[u]=sum[u<<1]+sum[u<<1|1];}ll query(int u,int l,int r,int a,int b){if(a<=l&&r<=b) return sum[u];pushdown(u,l,r);int mid=(l+r)>>1;ll res=0;if(a<=mid) res+=query(u<<1,l,mid,a,b);if(b>mid) res+=query(u<<1|1,mid+1,r,a,b);return res;} }; using namespace SegmentTree; int main(){init();n=read();for(int i=1;i<=n;i++)m[i]=read(),b[i]=read();get_nxt();q=read();for(int i=1;i<=q;i++){que[i].l=read();que[i].r=read();que[i].id=i;}sort(que+1,que+q+1);int tmp=n+1;for(int i=q;i>=1;i--){while(tmp>1&&tmp-1>=que[i].l){tmp--;add(1,1,n,tmp,nxt[tmp],1);//以tmp~nxt[tmp]為右端點(diǎn)的區(qū)間都多了一個 }ans[que[i].id]=query(1,1,n,que[i].l,que[i].r);}for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);return 0; }

    總結(jié)

    以上是生活随笔為你收集整理的[XSY] 智慧树(线性同余方程组,线段树/树状数组)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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