zoukankan      html  css  js  c++  java
  • 模拟12 题解

    A. 斐波那契(fibonacci)

    首先想到a,b<=1e6的暴力:建树,直接向上标记求lca。

    建树的过程中发现一个性质。

    斐波那契第n代兔子,是n-2代及以前的兔子的儿子。

    因为编号连续且与父亲编号大小有关,

    设该节点的编号为$x$,在第$k$代,

    则$f(x)=x-fib(k-1)$。

    二分查找父亲,向上标记求lca即可。

    (特判不换行,爆零两行泪)

    (见代码第25行)

     1 #include<iostream>
     2 #include<cstdio>
     3 #define ll long long
     4 using namespace std;
     5 ll fib[70],a,b;
     6 int m;
     7 inline ll read(){
     8     register ll x=0; char ch=getchar();
     9     while(!isdigit(ch)) ch=getchar();
    10     while(isdigit(ch)){
    11         x=(x<<1)+(x<<3)+(ch^48);
    12         ch=getchar();
    13     }
    14     return x;
    15 }
    16 int main(){
    17     fib[1]=fib[0]=1;
    18     for(int i=2;i<=65;++i) fib[i]=fib[i-1]+fib[i-2];
    19     m=read();
    20     while(m--){
    21         a=read(); b=read();
    22         if(b==a+1||a==b+1){
    23             printf("1");
    24             continue;
    25         }
    26         int x=lower_bound(fib,fib+63,a)-fib,y=lower_bound(fib,fib+63,b)-fib;
    27         if(fib[x]==a&&fib[y]==b){
    28             if((x-y)&1) printf("%d
    ",1);
    29             else printf("%lld
    ",min(a,b));
    30             continue;
    31         }
    32         while(a!=b){
    33             if(b<a) a-=fib[lower_bound(fib,fib+63,a)-fib-1];
    34             else b-=fib[lower_bound(fib,fib+63,b)-fib-1];
    35         }
    36         printf("%lld
    ",a);
    37     }
    38     return 0;
    39 }
    View Code

    B. 数颜色

    刚开始把题看成了数区间内不同颜色个数,于是一直在想怎么维护pre,怎么做到$O(nlogn)$。

    然后突然发现题目不一样,好像更简单了。

    然后就忘了考虑vector这些东西。

    打了个树状数组套主席树,

    然而出题人毒瘤,查询可能比最大的权值更大。

    70分死成了20分。

     

    正解是vector,交换的操作直接二分后swap即可。

    主席树也是可行的,交换邻项之后,后一项前缀和不变,对前一项的前缀和修改即可。

    复杂度都是$O(nlogn)$。

     1 #include<iostream>
     2 #include<vector>
     3 #include<cstdio>
     4 using namespace std;
     5 const int N=300010;
     6 int a[N],n,m;
     7 vector<int> ve[N];
     8 inline int read()
     9 {
    10     register int x=0; char ch=getchar();
    11     while(ch<'0'||ch>'9') ch=getchar();
    12     while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    13     return x;
    14 }
    15 int main(){
    16     n=read(); m=read();
    17     for(register int i=1;i<=n;++i) a[i]=read(),ve[a[i]].push_back(i);
    18     for(register int i=1,opt,l,r,x;i<=m;++i){
    19         opt=read();
    20         if(opt==1){
    21             l=read(); r=read(); x=read();
    22             printf("%d
    ",lower_bound(ve[x].begin(),ve[x].end(),r+1)-lower_bound(ve[x].begin(),ve[x].end(),l));
    23         }
    24         else{
    25             x=read();
    26             if(a[x]==a[x+1]) continue;
    27             swap(*lower_bound(ve[a[x]].begin(),ve[a[x]].end(),x),*lower_bound(ve[a[x+1]].begin(),ve[a[x+1]].end(),x+1));
    28             swap(a[x],a[x+1]);
    29         }
    30     }
    31     return 0;
    32 }
    vector
     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const int N=300010;
     5 struct node{
     6     node *lch,*rch;
     7     int val;
     8 }*root[N],pool[N*70],*ptr;
     9 int n,m,a[N],mx;
    10 void insert(node register *&p,const int l,const int r,const int pos,const int val){
    11     if(p) *ptr=*p;
    12     p=ptr++;
    13     if(l==r){
    14         p->val+=val;
    15         return ;
    16     }
    17     const int mid=l+r>>1;
    18     if(pos<=mid) insert(p->lch,l,mid,pos,val);
    19     else insert(p->rch,mid+1,r,pos,val);
    20 }
    21 inline int query(node *p,const int pos,int l=1,int r=mx){
    22     while(l!=r){
    23         if(!p) return 0;
    24         int mid=l+r>>1;
    25         if(pos<=mid) r=mid,p=p->lch;
    26         else l=mid+1,p=p->rch;
    27     }
    28     return p?p->val:0;
    29 }
    30 const int L=1<<20|1;
    31 char buffer[L],*S,*T;
    32 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
    33 inline int read()
    34 {
    35     register int x=0; char ch=getchar();
    36     while(ch<'0'||ch>'9') ch=getchar();
    37     while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    38     return x;
    39 }
    40 int main(){
    41     ptr=pool; n=read(); m=read();
    42     for(register int i=1;i<=n;++i) a[i]=read(),mx=max(mx,a[i]);
    43     for(register int i=1;i<=n;++i) root[i]=root[i-1],insert(root[i],1,mx,a[i],1);
    44     for(register int i=1,opt,l,r,x;i<=m;++i){
    45         opt=read();
    46         if(opt==1){
    47             l=read(); r=read(); x=read();
    48             if(x>mx){
    49                 puts("0");
    50                 continue;
    51             }
    52             printf("%d
    ",query(root[r],x)-query(root[l-1],x));
    53         }
    54         else{
    55             x=read();
    56             insert(root[x],1,mx,a[x],-1);
    57             insert(root[x],1,mx,a[x+1],1);
    58             swap(a[x],a[x+1]);
    59         }
    60     }
    61     return 0;
    62 }
    主席树(fread卡常)

    C. 分组

    从左向右考虑,设$dp(i)$表示由i点结束,分成最少的块。

    显然有$dp(i)=dp(j)+1$      $if( [j+1  ,  i]满足条件)$

    至于输出方案,转移时维护pre即可。

    转移的两个维度:dp值的大小,当前块是否满足条件。

    显然后者是有单调性的。

    也就是说,对于确定的右端点r,存在一个极坐的端点l,

    l以左均不满足条件,以右均满足条件。

    单调队列优化即可。

    (以上一段被没素质的yxs在没保存的状态下暴力关闭,导致我重打一遍,强烈谴责)

     

    然而这个dp是对的吗?

    题目要求输出字典序最小方案。

    最后一次的字典序最小,一定意味着全局最小吗?

    其实我已经在不知不觉中用了贪心。

    从右往左不断选,选到不能选时停止,得到的一定是最优答案。

    对于k=1,贪心或者dp都是可行的。

    对于k=2的情况,最好使用贪心来解决。

     

    对于k=1,

    因为权值和不大于$512^2$,

    将枚举i,j判断是否为平方数,

    转化为维护一个桶表示每个数出现次数,

    枚举平方数,减去i的权值,如果出现j就说明不合法。

    因为只有一个分组,不能存在任何两个数的和为平方数。

     

    对于k=2,

    同理维护一个桶。

    不妨将互相矛盾的点之间建边。

    将大组分为两个小组,其实等价于图中不存在奇环。

    也就是说,原图能够交叉染色,是一个二分图。

    暴力染色当然不是可行的,一种可行的,维护二分图的方法是:拓展域并查集。

    把每个数分为黑域和白域,当a,b加和为平方数,

    如果$find(a_{white})=find(b_{white})$,即存在矛盾。

    否则合并$a_{white}和b_{black},a_{black}和b_{white}$。

    然而如果存在相同的数,特判将很恶心。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<cstring>
     5 using namespace std;
     6 const int N=132000;
     7 int n,k,a[N],mx;
     8 inline int read(){
     9     int x=0; char ch=getchar();
    10     while(!isdigit(ch)) ch=getchar();
    11     while(isdigit(ch)){
    12         x=(x<<1)+(x<<3)+(ch^48);
    13         ch=getchar();
    14     }
    15     return x;
    16 }
    17 namespace case1{
    18     int cnt[N*2],dp[N],pre[N],q[N],front,tail;
    19     void dfs(int x){
    20         if(!x) return ;
    21         dfs(pre[x]); 
    22         printf("%d ",x);
    23     }
    24     void ooo(){
    25         front=tail=1; q[1]=0;
    26         for(int i=1;i<=n;++i){
    27             for(int j=2;j*j<=mx*2;++j){
    28                 while(front<tail&&j*j>a[i]&&cnt[j*j-a[i]]){
    29                     int l=q[front]+1,r=q[++front];
    30                     for(int o=l;o<=r;++o) --cnt[a[o]];
    31                 }
    32             }
    33             dp[i]=dp[q[front]]+1; pre[i]=q[front]; 
    34             while(front<=tail&&dp[i]<dp[q[tail]]) --tail;
    35             q[++tail]=i; ++cnt[a[i]];
    36         }
    37         printf("%d
    ",dp[n]);
    38         dfs(pre[n]);
    39         puts("");
    40     }
    41 }
    42 namespace case2{
    43     int cnt[N*2],f[N*2],stack[N],top,ans;
    44     bool ban[N];
    45     int find(int x){
    46         return f[x]==x?x:f[x]=find(f[x]);
    47     }
    48     void ooo(){
    49         for(int i=1;i<=mx*2;++i) f[i]=i;
    50         for(int i=2;i*i<=mx*2;++i) if(i%2==0) ban[i*i/2]=1;
    51         int l=n,r=n;
    52         while(r){
    53             while(l){
    54                 bool flag=1;
    55                 for(int i=2;i*i<=mx*2;++i)
    56                 {
    57                     if(i*i-a[l]!=a[l]) continue;
    58                     if(cnt[a[l]]==1) f[find(a[l])]=find(a[l]+mx);
    59                     if(cnt[a[l]]>=2) flag=0;
    60                 }
    61                 if(!flag) break;
    62                 for(int i=2;i*i<=mx*2;++i)
    63                     if(i*i-a[l]>0&&i*i-a[l]<=mx&&cnt[i*i-a[l]]&&i*i-a[l]!=a[l]){
    64                         int x_w=a[l],y_w=i*i-a[l],x_b=a[l]+mx,y_b=i*i-a[l]+mx;
    65                         if(cnt[i*i-a[l]]>=2&&ban[i*i-a[l]]) flag=0;
    66                         if(find(x_w)==find(y_w)) flag=0;
    67                         else f[find(x_w)]=find(y_b),f[find(x_b)]=f[find(y_w)];
    68                     }
    69                 if(!flag) break;
    70                 ++cnt[a[l--]];
    71             }
    72             for(int i=l;i<=r;++i) cnt[a[i]]=0,f[a[i]]=a[i],f[a[i]+mx]=a[i]+mx;
    73             r=l; ans++; if(r) stack[++top]=r;
    74         }
    75         printf("%d
    ",ans);
    76         while(top) printf("%d ",stack[top--]);
    77         puts("");
    78     }
    79 }
    80 int main(){
    81     //freopen("x.in","r",stdin);
    82     //freopen("me.out","w",stdout);
    83     n=read(); k=read();
    84     for(int i=1;i<=n;++i) a[i]=read(),mx=max(a[i],mx);
    85     if(k==1) case1::ooo();
    86     else case2::ooo();
    87     return 0; 
    88 }
    View Code
  • 相关阅读:
    #include< >和#include“ ”的区别
    第2章 基础语法 -- 运算符
    hive on spark的安装及问题
    第2章 Python基础语法 -- 数据类型
    第2章 Python基础语法--Hello python
    IT资源专业搜索-www.easysoo.cn
    学习英语
    zookeeper 安装
    Hadoop2.6 Ha 安装
    Hadoop平台安装前准备
  • 原文地址:https://www.cnblogs.com/skyh/p/11296117.html
Copyright © 2011-2022 走看看