• noip模拟测试12



    T1:斐波那契

      呃,其实这题手玩一下就秒出了,可是我还是zz的没有AC

      先说说我怎么zz的,$10^{12}$是13位……我还以为是12位,然后表就打小了gg

      

      其实正解很easy,手玩一下就会发现,点x的父亲就是x减去比x小的第一个斐波那契数

      然后就简单了,因为斐波那契树的层数是小于$log x_{max}$的

      所以直接用一个数向上跳父亲,并且记录经过了哪些点,然后再用另一个数一边向上跳,一边查就完了

      (于是大佬们纷纷#include<set>,只有蒟蒻我手写哈希表)

      so,code

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<queue>
     8 #include<vector>
     9 #define ll long long
    10 using namespace std;
    11 const int MAXN=300233,MAXD=2400;
    12 const ll D=2333;
    13 int m;
    14 ll f[65],a,b;
    15 struct hash_map {
    16     int h[MAXD],nxt[MAXD],tot,stk[MAXD],tp;
    17     ll val[MAXD];
    18     hash_map() {
    19         memset(h,0,sizeof(h));
    20         memset(nxt,0,sizeof(nxt));
    21         memset(val,0,sizeof(val));
    22     }
    23     void clear() {
    24         tot=0;
    25         while(tp) h[stk[tp--]]=0;
    26     }
    27     void insert(ll _v) {
    28         int p=_v%D;
    29         for(int i=h[p];i;i=nxt[i])
    30             if(val[i]==_v) return;
    31         if(!h[p]) stk[++tp]=p;
    32         val[++tot]=_v;
    33         nxt[tot]=h[p];
    34         h[p]=tot;
    35     }
    36     bool find(ll _v) {
    37         int p=_v%D;
    38         for(int i=h[p];i;i=nxt[i])
    39             if(val[i]==_v) return 1;
    40         return 0;
    41     }
    42 }mp;
    43 void first() {
    44     f[0]=f[1]=1;
    45     for(int i=2;i<=62;i++) f[i]=f[i-1]+f[i-2];
    46 }
    47 int main() {
    48     first();
    49     scanf("%d",&m);
    50     for(int i=1;i<=m;i++) {
    51         scanf("%lld%lld",&a,&b);
    52         mp.clear();
    53         mp.insert(a);
    54         for(int j=62;j>=1;j--)
    55             if(a>f[j]) {
    56                 a-=f[j];
    57                 mp.insert(a);
    58             }
    59         if(mp.find(b)) {
    60             printf("%lld
    ",b);
    61             continue;
    62         }
    63         for(int j=62;j>=1;j--)
    64             if(b>f[j]) {
    65                 b-=f[j];
    66                 if(mp.find(b)) {
    67                     printf("%lld
    ",b);
    68                     break;
    69                 }
    70             }
    71     }
    72     return 0;
    73 }
    t1 Code

     

    T2:数颜色
      考试时脑子被带修莫队填满了……
      详见数颜色专题
     
      code
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<queue>
     8 #include<vector>
     9 #define ll long long
    10 using namespace std;
    11 const int MAXN=300005;
    12 int n,m,a[MAXN],ans;
    13 vector<int> v[MAXN];
    14 inline int R() {
    15     int aa=0;char cc=getchar();
    16     while(cc>'9'||cc<'0')cc=getchar();
    17     while(cc>='0'&&cc<='9')aa=aa*10+cc-'0',cc=getchar();
    18     return aa;
    19 }
    20 int main() {
    21     scanf("%d%d",&n,&m);
    22     for(int i=1;i<=n;i++) {
    23         scanf("%d",&a[i]);
    24         v[a[i]].push_back(i);
    25     }
    26     for(int i=1,op;i<=m;i++) {
    27         op=R();
    28         if(op==1) {
    29             int l=R(),r=R(),c=R();
    30             int al=lower_bound(v[c].begin(),v[c].end(),l)-v[c].begin();
    31             int ar=upper_bound(v[c].begin(),v[c].end(),r)-v[c].begin();
    32             printf("%d
    ",ar-al);
    33         } else {
    34             int tmp=R();
    35             if(a[tmp]!=a[tmp+1]) {
    36                 int t1=lower_bound(v[a[tmp]].begin(),v[a[tmp]].end(),tmp)-v[a[tmp]].begin();
    37                 int t2=lower_bound(v[a[tmp+1]].begin(),v[a[tmp+1]].end(),tmp+1)-v[a[tmp+1]].begin();
    38                 ++v[a[tmp]][t1];
    39                 --v[a[tmp+1]][t2];
    40                 swap(a[tmp],a[tmp+1]);
    41             }
    42         }
    43     }
    44     return 0;
    45 }
    t2 Code


    T3:分组

      看到时一脸懵比,脑子里只有贪心……

      那就贪心吧,只会写$k=1$的情况

      于是就要快速判断一群数分别加某个数是否能得到一个特定的值

      就想到这道题:小清新人渣的本愿

      于是用bitset来解决这个问题,复杂度 $n/32$,但考完后发现其实$sqrt{n}$的暴力枚举更快……

      

      说说正解:

        case $k=1$:

          暴力扫一遍,如果能加入当前段就加入,否则就清空数组并分段

          判断能否加入直接暴力扫一遍值域内所有的平方数,看平方数减当前数的得数是否出现过

          因为要求字典序最小,所以贪心的倒着加入就完了

        case $k=2$:

          分析后会发现,如果将刚刚的情况看作是把一段数往一个桶里塞的话

          那么现在的操作就可以看作是把一段数往两个桶里塞,每个桶里的数不能冲突

          贪心的想,会发现如果出现一个与桶中的数冲突的数,就一定得将其塞到另一个桶里

          如果这个数和两个桶中的数都有冲突,那就必须得分段

          那怎么维护呢?

          用带扩展域的并查集啊

          即:1,3冲突,则将1 和 3',1’ 和 3 分别merge一起

            表示条件“有1”和“无3”在一个集合,“无1”和“有3”在一个集合

          若某一时刻出现了“有a”和"无a"在一个集合的情况,则需要新分一个段

          

          但这样还有一点问题,因为每个数有可能多次出现,所以会出现几种特殊情况:

            若数a满足$2*a=x^2$

            1.当a第二次出现时,若已经有和a冲突的数

             那两个桶中一个有a,另一个有和a冲突的数,那么新的a便无法加入桶中,于是需要再分一段

            2.当集合中没有与a冲突的数,但a出现了第三次,那么新的a便无法加入桶中,于是需要再分一段

            3.当插入其他数时,发现该数与a冲突,且a已经出现了两次,则无法加入该数,于是需要再分一段

          于是需要特判一下满足$2*a=x^2$的数

        然后像$k=1$的时候一样倒着贪心的加入就好了。

        

        特判比较多,需要思路清晰时食用

        so,code

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<queue>
     8 #include<vector>
     9 #define ll long long
    10 using namespace std;
    11 const int MAXN=200000;
    12 int n,k,a[MAXN],m,ans[MAXN],stk[MAXN],tp,mx;
    13 int fa[MAXN*2],bstk[MAXN*2],btp,vis[MAXN*2];
    14 bool spl[MAXN*2],bvis[MAXN*2];
    15 void work1() {
    16     for(int i=n;i>=1;i--) {
    17         for(int j=2;j<=512;j++)
    18             if(j*j>a[i]&&vis[j*j-a[i]]) {
    19                 while(tp) vis[stk[tp--]]=0;
    20                 ans[++m]=i;
    21             }
    22         if(!vis[a[i]]) stk[++tp]=a[i],vis[a[i]]=1;
    23     }
    24 }
    25 int get(int x) {
    26     if(!bvis[x]) bstk[++btp]=x,bvis[x]=1;
    27     if(x==fa[x]) return x;
    28     return fa[x]=get(fa[x]);
    29 }
    30 void merge(int x,int y) {
    31     int fx=get(x),fy=get(y);
    32     if(fx!=fy) fa[fx]=fy;
    33 }
    34 void work2() {
    35     for(int i=1;i<=2*mx;i++) fa[i]=i;
    36     for(int i=2;i<=512;i++)
    37         if(!((i*i)&1)) spl[i*i/2]=1;
    38     for(int i=n;i>=1;i--) {
    39         for(int j=2;j<=512;j++) {
    40             if(j*j>a[i]&&vis[j*j-a[i]]) {
    41                 if(j*j==2*a[i]) continue;
    42                 if(spl[j*j-a[i]]&&vis[j*j-a[i]]>=2) {
    43                     merge(a[i],a[i]+mx);
    44                     break;
    45                 }
    46                 merge(a[i],j*j-a[i]+mx);
    47                 merge(a[i]+mx,j*j-a[i]);
    48             }
    49         }
    50         if(spl[a[i]]&&vis[a[i]]) {
    51             if(vis[a[i]]>=2) merge(a[i],a[i]+mx);
    52             else for(int j=2;j<=512;j++)
    53                     if(j*j>a[i]&&vis[j*j-a[i]]) {
    54                         if(j*j==2*a[i]) continue;
    55                         merge(a[i],a[i]+mx);
    56                         break;
    57                     }
    58         }
    59         if(get(a[i])==get(a[i]+mx)) {
    60             ans[++m]=i;
    61             while(tp) vis[stk[tp--]]=0;
    62             while(btp) fa[bstk[btp]]=bstk[btp],bvis[bstk[btp]]=0,--btp;
    63         }
    64         if(!vis[a[i]]) stk[++tp]=a[i];
    65         ++vis[a[i]];
    66     }
    67 }
    68 int main() {
    69     scanf("%d%d",&n,&k);
    70     for(int i=1;i<=n;i++) scanf("%d",&a[i]),mx=max(mx,a[i]);
    71     if(k==1) work1();
    72     else work2();
    73     printf("%d
    ",m+1);
    74     for(int i=m;i>=1;i--) printf("%d ",ans[i]);
    75     printf("
    ");
    76     return 0;
    77 }
    t3 Code

  • 相关阅读:
    progresql
    postgresql
    postgresql
    postgresql 索引
    postgresql 视图
    postgresql 触发器
    postgresql异常快速定位
    postgresql数据库备份和恢复
    amgular $q用法
    安装fcitx
  • 原文地址:https://www.cnblogs.com/Gkeng/p/11295447.html
Copyright © 2020-2023  润新知