一些板子
在此记录一些本人百打百挂的板子:
1. 扩展欧几里得(以青蛙的约会为模板)
题意:给出n,m,x,y,l,求g*l+k*(n-m)=x-y中k的最小正整数解
做法:明显是扩欧板子虽然我不会写
注意n-m为负数时,将n-m与x-y同时取相反数即可
记住x=y1,y=x1-a/b*y1
当求出ax+by=gcd(a,b)的特解后,通解为y=y0-(a/gcd)*t,x=x0+(b/gcd)*t
上代码
#include <cstdio> inline long long int gcd(long long int a,long long int b){return b==0?a:gcd(b,a%b);} inline void exgcd(long long int a,long long int b,long long int &x,long long int &y){ if(b==0){ x=1,y=0; return; } long long int x1,y1; exgcd(b,a%b,x1,y1); x=y1,y=x1-a/b*y1; return; } int main(void){ long long int xx,yy,mm,nn,ll; scanf("%lld%lld%lld%lld%lld",&xx,&yy,&mm,&nn,&ll); long long int a=ll,b=mm-nn,c=yy-xx; if(b<0) b=-b,c=-c; long long int d=gcd(a,b); if(c%d){ printf("Impossible"); return 0; } else{ a/=d,b/=d,c/=d; long long int x,y; exgcd(a,b,x,y); printf("%lld\n",((y*c)%a+a)%a); } }
2. 单调队列(以琪露诺为模板)
题目描述:(车 万 厨 狂 喜)
在幻想乡,琪露诺是以笨蛋闻名的冰之妖精。
某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来。但是这只青蛙比以往的要聪明许多,在琪露诺来
之前就已经跑到了河的对岸。于是琪露诺决定到河岸去追青蛙。
小河可以看作一列格子依次编号为0到N,琪露诺只能从编号小的格子移动到编号大的格子。而且琪露诺按照一种
特殊的方式进行移动,当她在格子i时,她只移动到区间[i+l,i+r]中的任意一格。你问为什么她这么移动,这还不简
单,因为她是笨蛋啊。
每一个格子都有一个冰冻指数A[i],编号为0的格子冰冻指数为0。当琪露诺停留在那一格时就可以得到那一格的
冰冻指数A[i]。琪露诺希望能够在到达对岸时,获取最大的冰冻指数,这样她才能狠狠地教训那只青蛙。
但是由于她实在是太笨了,所以她决定拜托你帮它决定怎样前进。
开始时,琪露诺在编号0的格子上,只要她下一步的位置编号大于N就算到达对岸。
做法: 单调队列模板题之一(还有一个叫滑动窗口的我写了三遍Orz)
记住一句话-->当一个选手比你小,还比你强,你就可以退役了
上代码
1 #include <cstdio> 2 #include <cstring> 3 #define int long long int 4 5 int a[300005],dp[300005],last[300005],queue[300005]; 6 int step[300005]; 7 8 signed main(void){ 9 memset(dp,-0x3f,sizeof(dp)); 10 int n,l,r; 11 scanf("%lld%lld%lld",&n,&l,&r); 12 for(int i=0;i<=n-1;i++) scanf("%lld",&a[i]); 13 14 dp[0]=0; 15 int head=1,tail=0; 16 for(int i=l;i<=n+r;i++){ 17 while(head<=tail&&dp[i-l]>dp[queue[tail]]) tail--; 18 while(head<=tail&&queue[head]<i-r) head++; 19 queue[++tail]=i-l; 20 dp[i]=dp[queue[head]]+a[i]; 21 last[i]=queue[head]; 22 } 23 24 int maxx_loc,maxx=-99999999999999; 25 for(int i=n+r-1;i>n;i--) if(dp[i]>=maxx) maxx_loc=i,maxx=dp[i]; 26 27 int cntt=0; 28 for(int i=maxx_loc;i;i=last[i]){ 29 step[++cntt]=i; 30 } 31 printf("%lld\n",maxx); 32 /*printf("0 "); 33 for(int i=cntt;i>1;i--) printf("%I64d ",step[i]); 34 printf("-1");*/ 35 }
3. tarjan求强联通分量(以上白泽慧音为模板(((
题目描述:(车 万 厨 狂 喜 + +)
在幻想乡,上白泽慧音是以知识渊博闻名的老师。
春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一
个能够聚集最多人数的村庄作为新的教学地点。
人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用
1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。
当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个
集合中任意两个村庄X,Y都满足<X,Y>。
现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,
输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。
做法: tarjan模板题,没啥好说的
上代码
1 #include <cstdio> 2 #include <stack> 3 #include <vector> 4 using namespace std; 5 6 stack<int> s; 7 vector<int> v[50005]; 8 9 struct node{ 10 int to,next; 11 }e[100005]; 12 13 int tarjan_cnt=0,cnt=0,color_cnt=0; 14 int head[50005],dfn[50005],low[50005],color[50005],color_num[50005]; 15 bool vis[50005]; 16 17 inline void add(int from,int to){ 18 e[++cnt].to=to; 19 e[cnt].next=head[from]; 20 head[from]=cnt; 21 } 22 23 inline int tarjan(int now){ 24 s.push(now); 25 dfn[now]=low[now]=++tarjan_cnt; 26 vis[now]=1; 27 28 for(int i=head[now];i;i=e[i].next){ 29 if(!dfn[e[i].to]){ 30 tarjan(e[i].to); 31 low[now]=min(low[now],low[e[i].to]); 32 } 33 else if(vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); 34 } 35 36 if(dfn[now]==low[now]){ 37 vis[now]=0; 38 color[now]=++color_cnt; 39 40 while(1){ 41 int noww=s.top(); 42 s.pop(); 43 vis[noww]=0; 44 color[noww]=color_cnt; 45 color_num[color_cnt]++; 46 if(noww==now) break; 47 } 48 } 49 } 50 51 int main(void){ 52 int n,m; 53 scanf("%d%d",&n,&m); 54 55 for(int i=1;i<=m;i++){ 56 int from,to,t; 57 scanf("%d%d%d",&from,&to,&t); 58 if(t==2) add(to,from); 59 add(from,to); 60 } 61 62 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 63 for(int i=1;i<=n;i++) v[color[i]].push_back(i); 64 65 int biaoji=0,maxx=0,minn_2=999999999; 66 for(int i=1;i<=color_cnt;i++){ 67 if(color_num[i]>maxx) maxx=color_num[i],biaoji=i,minn_2=v[i][0]; 68 else if(color_num[i]==maxx) if(v[i][0]<minn_2) biaoji=i; 69 } 70 71 printf("%d\n",maxx); 72 for(int i=0;i<v[biaoji].size();i++) printf("%d ",v[biaoji][i]); 73 }