8.3题解

T1[洛谷P3938]

题目很明显了,菲波那契,找规律无疑了,考场上的话,如果你对菲波那契足够敏感,那我想你是可以想到正解的,毕竟考场14个人AC,还算挺水的,如果实在想不出来,可以暴力打表找一下父亲,毕竟你是要不停的翻父亲,不管用什么方法吧,最后会发现$fa[x]=x-fib(x的出生月份-1)$,那我们再考虑一下对于$le12$的数据,他不停的翻父亲最多会翻多少遍,你会发现也就60遍,这个时候这道题就可做了,甚至不需要倍增,完全可以直接翻,但是由于你不知道深度,所以需要先把两个点分别翻一遍,找到深度,然后用类似于倍增$lca$的方法直接翻就可以了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<set>
 4 #define maxf 62
 5 #define re register
 6 #define ll long long
 7 using namespace std;
 8 const int L=1<<20|1;
 9 char buffer[L],*S,*T;
10 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
11 ll m;
12 ll f[maxf];
13 set <ll> ccc;
14 inline ll read()
15 {
16     re ll aa=0,bb=1;re char cc=getchar();
17     while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
18     while(cc<='9'&&cc>='0'){aa=aa*10+cc-'0';cc=getchar();}
19     return aa*bb;
20 }
21 inline int ef(re ll x)
22 {
23     re int l=1,r=61;
24     while(l<r)
25     {
26         if(l+1==r)
27         {
28             if(x>f[l])  return r;
29             else  return l;
30         }
31         re int mid=(l+r)>>1;
32         if(x>f[mid])  l=mid+1;
33         else  r=mid;
34     }
35     return l;
36 }
37 int main()
38 {
39     m=read();
40     f[0]=1;  f[1]=1;
41     for(re int i=2;i<maxf;++i)  f[i]=f[i-1]+f[i-2];
42     for(re int i=1;i<=m;++i)
43     {
44         ll a=read(),b=read();  ll ls1=a,ls2=b;
45         int deepa=0,deepb=0;
46         while(ls1>1)  {deepa++;  ls1-=f[ef(ls1)-1];}
47         while(ls2>1)  {deepb++;  ls2-=f[ef(ls2)-1];}
48         if(deepa<deepb)  {swap(deepa,deepb);  swap(a,b);}
49         while(deepa>deepb)  {a-=f[ef(a)-1]; deepa--;}
50         while(a!=b)  {a-=f[ef(a)-1];  b-=f[ef(b)-1];}
51         printf("%lld\n",a);
52     }
53     return 0;
54 }
View Code

T2[洛谷P3939]

这题和BZOJ2120相似度不是一般的高啊,$BZOJ2120$可是个带修莫队的板子题,不过很可惜,我并没有学,后来颓了题解之后,给我一种这题很简单的感觉,只要$STL$可以6到飞起,这题就没问题,这题二元组排序,颜色做第一维,位置做第二维,先来考虑一下修改操作吧,你会发现他是交换$x$和$x+1$的位置,那对于你排好的序列是没有影响的,只要改掉位置就可以了,所以只需要lower_bound找到要修改的点,把第二维改一下就可以了,不过由于lower_ bound的特殊性,平常结构题进行二元组排序的思路被舍弃了,这时候有出现了一个新的$STL$:$pair$,其实就是个结构体,只不过已经定义好了,且只有两维,具体的实现方法可以参照下面的代码,修改搞定了,然后就是询问了,既然是按照颜色排序,那就只需要一个upper_bound和一个lower_bound,分别用来查找第一个大于$r$的位置和第一个大于等于$l$的位置,做差即可

话说这题打$treap$,主席树,树套树等等,各种数据结构,大力卡常都可以拿到一个不错的成绩,$treap$都可以直接A

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define maxn 300100
 5 using namespace std;
 6 pair <int,int> a[maxn];
 7 int n,m;
 8 int Cc[maxn];
 9 inline int read(){
10     register int ret;
11     register char r;
12     while(r=getchar(),r<'0'||r>'9');ret=r-48;
13     while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48;
14     return ret;
15 }
16 int main()
17 {
18     n=read();  m=read();
19     for(int i=1;i<=n;++i)  {a[i].first=read();  Cc[i]=a[i].first;  a[i].second=i;}
20     sort(a+1,a+n+1);
21     for(int i=1;i<=m;++i)
22     {
23         int opt=read();
24         if(opt==1)
25         {
26             int l=read(),r=read(),Col=read();
27             pair <int,int> ls;
28             ls.first=Col;  ls.second=l;
29             int wz1=lower_bound(a+1,a+n+1,ls)-a;
30             pair <int,int> lss;
31             lss.first=Col;  lss.second=r;
32             int wz2=upper_bound(a+1,a+n+1,lss)-a;
33             int ans=wz2-wz1;
34             printf("%d\n",ans);
35         }
36         else
37         {
38             int x=read();
39             if(Cc[x]==Cc[x+1])  continue;
40             else
41             {
42                 int ls=Cc[x];
43                 pair <int,int> ls1;
44                 ls1.first=Cc[x];  ls1.second=x;
45                 int wz1=lower_bound(a+1,a+n+1,ls1)-a;
46                 a[wz1].second=x+1;  Cc[x]=Cc[x+1];
47                 pair <int,int> ls2;
48                 ls2.first=Cc[x+1];  ls2.second=x+1;
49                 int wz2=lower_bound(a+1,a+n+1,ls2)-a;
50                 a[wz2].second=x;  Cc[x+1]=ls;
51             }
52         }
53     }
54     return 0;
55 }
View Code

 

T3[洛谷P3940]

这题$k==1||k==2$一看就友好啊,先骗8分没问题

说实话$k==1$就是个暴力,因为每个块内都不能冲突,所以暴力扫一遍,碰到冲突的直接分组就可以了,字典序最小的话就是前面多分组,后面少分组呗,那从后向前扫,直接贪心就可做,不过如果暴力扫当前块中的数,判是否冲突的话,很大的可能性会T,我们会发现他有一个有趣的性质,最大的数为什么是131072呢,一般不都应该是$le$几之类的数嘛,好巧不巧,两个131072加和,恰好是$512^2$,那我们枚举512,肯定比枚举当前块所有的数划算啊,所以,直接枚举到512,列出所有的平方数,和当前准备加入的点做差,看看这个差是否存在在当前组内就可以了

对于$k==2$,和关押罪犯有些像,而这两道题,用并查集或交叉染色判二分图都可做,我用的二分图,每加入一个点,就对当前组内所有的点跑一遍二分图,如果不能构成二分图,直接分组即可,并查集的思想和这个类似,依旧是从后往前扫贪心

$tips$:清空的时候不要$memset$,放进去几个点清空几个点,不然一不注意就会T,不过一定要清空啊!!还有就是重复的点,建图的时候别忘了

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<vector>
  5 #include<cstring>
  6 #define maxn 270000
  7 using namespace std;
  8 /*const int L=1<<20|1;
  9 char buffer[L],*S,*T;
 10 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)*/
 11 int n,k,js=1;
 12 int a[maxn],ans[maxn],pd[maxn];
 13 vector <int> b[maxn],bb[maxn],c[maxn];
 14 int jss,bjjj;
 15 int head[maxn],to[maxn*2],xia[maxn*2],visit[maxn];
 16 inline int read()
 17 {
 18     int ret;
 19     char r;
 20     while(r=getchar(),r<'0'||r>'9');ret=r-48;
 21     while(r=getchar(),r>='0'&&r<='9')ret=ret*10+r-48;
 22     return ret;
 23 }
 24 void add(int x,int y)
 25 {
 26     to[++jss]=y;  xia[jss]=head[x];  head[x]=jss;
 27 }
 28 void dfs(int x,int colo)
 29 {
 30     visit[x]=colo;
 31     for(int i=head[x];i;i=xia[i])
 32     {
 33         int ls=to[i];
 34         if(ls<=bb[js][0])
 35         {
 36             if(visit[ls]==0)  dfs(ls,3-colo);
 37             else if(visit[ls]==colo)  {bjjj=1;  return ;}
 38         }
 39     }
 40 }
 41 int main()
 42 {
 43 //    freopen("division18.in","r",stdin);
 44     n=read();  k=read();
 45     for(int i=1;i<=n;++i)  a[i]=read();
 46     if(k==1)
 47     {
 48         int zz=n;
 49         while(zz>0)
 50         {
 51             if(b[js].size()!=0)
 52                 for(int i=2;i<=512;++i)
 53                 {
 54                     int ls1=i*i-a[zz];
 55                     if(pd[ls1]==1)
 56                     {
 57                         for(int i=0;i<b[js].size();++i)  pd[b[js][i]]=0;
 58                         ans[++js]=zz;  break;
 59                     }
 60                 }
 61             b[js].push_back(a[zz]);  pd[a[zz]]=1;  zz--;
 62         }
 63         printf("%d\n",js);
 64         for(int i=js;i>=2;--i)  printf("%d ",ans[i]);
 65         puts("");
 66     }
 67     else
 68     {
 69         for(int i=n;i>=1;--i)
 70         {
 71             if(b[js].size()==0)
 72             {
 73                 b[js].push_back(a[i]);  bb[js].push_back(i);
 74                 pd[a[i]]=1;  c[a[i]].push_back(i);
 75                 continue;
 76             }
 77             for(int j=2;j<=512;++j)
 78             {
 79                 int ls1=j*j-a[i];  bjjj=0;
 80                 if(pd[ls1]!=0)
 81                 {
 82                     for(int k=0;k<c[ls1].size();++k)
 83                         if(js==1||c[ls1][k]<=bb[js][0])
 84                             {add(c[ls1][k],i);  add(i,c[ls1][k]);}
 85                     for(int k=0;k<bb[js].size();++k)  visit[bb[js][k]]=0;
 86                     for(int k=0;k<bb[js].size();++k)
 87                         if(visit[bb[js][k]]==0)  dfs(bb[js][k],1);
 88                     for(int k=0;k<bb[js].size();++k)  visit[bb[js][k]]=0;
 89                     visit[i]=0;
 90                 }
 91                 if(bjjj==1)
 92                 {
 93                     for(int k=1;k<=jss;++k)  {to[k]=0;  xia[k]=0;}
 94                     for(int k=0;k<b[js].size();++k)
 95                                             {head[bb[js][k]]=0;  pd[b[js][k]]=0;}
 96                     head[i]=0;  jss=0;  js++;
 97                 }
 98             }
 99             b[js].push_back(a[i]);  bb[js].push_back(i);
100             c[a[i]].push_back(i);  pd[a[i]]=1;
101         }
102         printf("%d\n",js);
103         for(int i=js;i>=2;--i)  printf("%d ",bb[i][0]);
104         puts("");
105     }
106     return 0;
107 }
View Code

 

posted @ 2019-08-04 19:41  hzoi_X&R  阅读(170)  评论(0编辑  收藏  举报