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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

专题:数列信息传递问题转化为图论合点问题(ybtoj-数列询问+序列破解)

發布時間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 专题:数列信息传递问题转化为图论合点问题(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-数列询问+序列破解)的全部內容,希望文章能夠幫你解決所遇到的問題。

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