专题:数列信息传递问题转化为图论合点问题(ybtoj-数列询问+序列破解)
文章目錄
- 前言:
- 一、數列詢問(取模)
- 解析
- 代碼
- 二、序列破解(奇偶性)
- 解析
- 代碼
- thanks for reading!
前言:
在一個數列a中,對于一個大區間A和組成它的兩個小區間a,b;
可以借其中兩個區間的信息推導出第三個區間的信息
不妨稱這樣的問題叫做數列的信息傳遞問題
(具體來說就是:給出[l1,r1]的信息與[r1,r2]的信息(這里也可能是[r1+1,r2],只是在連點的細節上略有不同),那么就可以求出[l1,r2]的信息)
看一個例子:
若分別已知區間[1,4][5,7][8,10][11,15]的總和的奇偶性
那么顯然可以推出[1,15]的總和的奇偶性
從上面可以看出:這種信息推導具有傳遞性
那么對于這樣的問題,我們可以將其轉化為點的合并問題
本文所舉的具有這樣性質的信息有兩個,一個是加和奇偶性,一個是取模
那么我們開始吧:
一、數列詢問(取模)
解析
這道題提供了并查集一種新的用處:
合并過程中的狀態轉移
從前綴和來看:
每次的詢問相當于
(sum[r]-sum[l-1])%p=k
我們把l-1合并到r上
fa[i]表示第i個數的父親結點
num[i]表示 (sum[ fa[i] ] - sum[i])%p的結果
再加上一些奇奇怪怪的狀態轉移(讀者不妨自己推導一下)與判斷就ok了~
代碼
#include<cmath> #include<algorithm> #include<cstdio> #include<cstring> #include<iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int N=1e6+100; const int M=10; const int mod=100; int m,n,t,p; ll ans; int a,b,c,d; int num[N],fa[N]; int find(int x){if(fa[x]==x) return x;int ex=fa[x];fa[x]=find(fa[x]);num[x]=(num[ex]+num[x])%p;return fa[x]; } void merge(int x,int y,int z){int xx=fa[x],yy=fa[y];fa[xx]=yy;num[xx]=(num[y]-num[x]-z+2*p)%p;return; } int main(){scanf("%d%d%d",&n,&m,&p);for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=m;i++){scanf("%d%d%d",&a,&b,&c);a--;int aa=find(a),bb=find(b);if(aa==bb){if((num[a]-num[b]+p)%p==c) continue; // else if(num[a]==0&&num[b]==c) continue; // else if(num[b]==0&&num[a]==c) continue;else{printf("%d",i-1);return 0;}}else{merge(a,b,c);}}printf("%d",m);return 0; } /* 10 5 2 1 2 0 3 4 1 5 6 0 1 6 0 7 10 1 */二、序列破解(奇偶性)
解析
要想知道點k的值,我們必須通過一組[l,k-1]與[l,k]的信息求得;
那么是不是意味著每次對于[l,r]的詢問就意味著把點l與點r合并呢?
不是的!
經過推導不難發現:
我們已知[l,r1]和[r1+1,r2]的奇偶性時,才能獲得[l,r2]的信息;
而按照剛才的做法,顯然是錯誤的!
所以需要一些微妙的調整
我們發現:
若每次對于[l,r]的詢問,把點l-1與r合并,就能使這個問題得到很好的解決
(把點l與r+1合并也可以,是一個道理)
那么我們就只需要保證每個點都與前一個點聯通即可
那么顯然最后所有的點都會聯通
問題就轉化為了最小生成樹問題
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) const int N=4e6+100; int n,m; int fa[N]; int find(int x){if(fa[x]==x) return x;return fa[x]=find(fa[x]); } struct node{int x,y;ll v;bool operator < (const node y)const{return v<y.v;} }p[N]; int num; ll ans; ll a,b,c; int main(){scanf("%d",&n);for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=n;i++){for(int j=i;j<=n;j++){scanf("%lld",&a);p[++num]=(node){i-1,j,a}; }}sort(p+1,p+1+num);for(int i=1;i<=num&&m<n;i++){int xx=find(p[i].x),yy=find(p[i].y);if(xx==yy) continue;fa[xx]=yy;m++;ans+=p[i].v;}printf("%lld",ans);return 0; }thanks for reading!
總結
以上是生活随笔為你收集整理的专题:数列信息传递问题转化为图论合点问题(ybtoj-数列询问+序列破解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 桀怎么读 汉字桀怎么读
- 下一篇: 不止代码:循环比赛(分治)