• 「模拟8.19 A嚎叫..(set) B主仆..(DFS) C征程..(DP+堆优化)」


    为啥这一套题目背景感到很熟悉。

    T1  嚎叫响彻在贪婪的厂房

    考试一个小时没调出来,自闭了..........

    正解很好想,最后实在打不出来了只好暴力骗分了。。。

    联想到以前做的题:序列(涉及质因数分解)

    对于此题需要注意

    1.等差数列中不能有相同的数,所以可以用set判断

    2.同时对于等差数列我们可以用gcd判断,

    设当前数为a[i],定义变量gcdd,那么就将其与a[i-1]的差的绝对值与gcdd取gcd

    因为当前的两个数的gcd不见得是序列真正的gcd,但他只会比真正的gcd要大,所以我们通过此可以缩小gcdd的范围,

    然后注意删除是清空

     1 #include<cmath>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<cmath>
     5 #include<cstdio>
     6 #include<cstring>
     7 #include<algorithm>
     8 #include<map>
     9 #include<set>
    10 #include<vector>
    11 #define MAXN 200020
    12 #define int long long
    13 using namespace std;
    14 set<int>s;
    15 int gcd(int a,int b)
    16 {
    17     return (b==0)?a:gcd(b,a%b);
    18 }
    19 int n,a[MAXN];int ans=0;int gcdd;    
    20 set<int>::iterator it;
    21 bool find(int x)
    22 {
    23      //printf("it%lld
    ",*it);
    24      int gg=abs(*it-x);
    25      if(s.size()==2)gcdd=gg;
    26      //printf("gg=%lld gcd=%lld
    ",gg,gcdd);
    27      if(gcd(gg,gcdd)<=1)
    28      {
    29          return 0;
    30      }
    31      else 
    32      {
    33          gcdd=gcd(gg,gcdd);
    34          return 1;
    35      }
    36 }
    37 signed main()
    38 {
    39     scanf("%lld",&n);
    40     for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    41     for(int i=1;i<=n;++i)
    42     {
    43         //printf("i==========%lld
    ",i);
    44         if(s.size()==0){s.insert(a[i]);it=s.begin();gcdd=0;}
    45         else 
    46         {        
    47             if(s.count(a[i])!=0)
    48             {
    49                 s.clear();
    50                 ans++;
    51                 s.insert(a[i]);
    52                 it=s.begin();              
    53                 gcdd=0;
    54             }
    55             else if(abs(a[i]-a[i-1])==1)
    56             {
    57                 s.clear();
    58                 ans++;
    59                 s.insert(a[i]);
    60                 it=s.begin();
    61                 gcdd=0;
    62             }
    63             else
    64             {
    65                s.insert(a[i]);            
    66                if(find(a[i])==0)
    67                {
    68                     s.clear();
    69                     gcdd=0;
    70                     s.insert(a[i]);
    71                     ans++;
    72                     it=s.begin();              
    73                     //if(i<=75&&i>=69)
    74                     //printf("--%lld i=%lld ans=%lld
    ",a[i],i,ans);
    75                }             
    76             }
    77             //printf("ans=%lld
    ",ans);
    78         }
    79     }
    80     printf("%lld
    ",ans+1);
    81 }
    82 /*
    83 5
    84 631061 
    85 1 
    86 925917 
    87 6 
    88 8 
    89 */
    View Code

    T2 主仆见证了 Hobo 的离别考试读错题还能水到40分????用了bitset的错解不再说了,从网上大佬那学了bitset的用法.....

    然后是正(bao)解(li)

    首先这题的记忆不是具体的数值,所以不能用bitset暴力求并集交集,因为这样并集根本不存在

    于是我们连边,对于交集,我们将k个点向新点连边表示控制

    并集反之,然后我暴力水过了,大佬勿看.........

     1 #include<bits/stdc++.h>
     2 #define MAXN 500000
     3 #define int long long
     4 using namespace std;
     5 int head[MAXN],tot;
     6 struct node{int to,n;}e[MAXN*2];
     7 void add(int u,int v){e[++tot].to=v;e[tot].n=head[u];head[u]=tot;}
     8 int n,m;int id;int orz;
     9 bool ok=0;
    10 bool vis[MAXN];int ss[MAXN];
    11 void clear()
    12 {
    13      for(int i=1;i<=ss[0];++i)vis[ss[i]]=0;
    14      ss[0]=0;
    15 }
    16 void DFS(int x,int y)
    17 {
    18      vis[x]=1;ss[++ss[0]]=x;
    19      if(x==y){ok=1;return ;}
    20      for(int i=head[x];i;i=e[i].n)
    21      {
    22          int to=e[i].to;
    23          if(vis[to])continue;
    24          vis[to]=1;
    25          DFS(to,y);
    26          if(ok==1)return ;
    27      }
    28 }
    29 signed main()
    30 {
    31      scanf("%lld%lld",&n,&m);
    32      id=n;
    33      for(int i=1;i<=m;++i)
    34      {
    35          scanf("%lld",&orz);
    36          if(orz==1)
    37          {
    38              ok=0;int x,y;
    39              scanf("%lld%lld",&x,&y);
    40              DFS(y,x);
    41              cout<<ok<<endl;
    42              clear();
    43          }
    44          else
    45          {
    46              int opt;
    47              scanf("%lld",&opt);
    48              ++id;
    49              if(opt==0)
    50              {
    51                 int k;
    52                 scanf("%lld",&k);
    53                 if(k==1){int x;scanf("%lld",&x);add(x,id);add(id,x);continue;}
    54                 for(int i=1;i<=k;++i)
    55                 {
    56                     int x;
    57                     scanf("%lld",&x);
    58                     add(x,id);
    59                 }
    60              }
    61              else
    62              {
    63                 int k;
    64                 scanf("%lld",&k);
    65                 if(k==1){int x;scanf("%lld",&x);add(x,id);add(id,x);continue;}                 
    66                 for(int i=1;i<=k;++i)
    67                 {
    68                     int x;
    69                     scanf("%lld",&x);
    70                     add(id,x);                
    71                 }                
    72              }
    73          }
    74      }
    75 }
    View Code

    T3 征途堆积出友情的永恒

    这是个DP优化的好题,不知道为啥大家这么快就改过来了........

    对于线性的DP方程很好推啊,f[i]表示从那下车的费用

    f[i]=min(f[j]+max(b[j],sum[i]-sum[j]),f[i])(j>=i-k)

    对于该方程我们考虑优化,因为f[j]-sum[j],f[j]+b[j]是一定的,所以我们考虑用堆维护

    但是一个堆显然无法存储两个值,于是我们开两个堆

    sum1记录f[j]+b[j],sum2记录f[j]-sum[j];

    然后因为我们需要的是max(sum[i]-sum[j],b[j]),那么我们不能直接将两个值放进去

    那么我们考虑在两个堆中放进不同的j值,保证两个堆的j不会重复,

    这样当我们取出两个堆的值时他们一定是当前j的情况下max(sum[i]-sum[j],b[j])

    但是由于sum[i]是变化的那么堆里的值也会变化

    我们发现sum1里维护的值是不变的,那么例如

    在i==2时取出sum1的堆顶此时的堆顶是j,我们发现f[j]+b[j]>f[j]+sum[i]-sum[j],证明对于j的位置,我是选f[j]+b[j]的情况我们当然可以选

    但是i==3取出j,我们发现f[j]+b[j]<f[j]+sum[i]-sum[j],这时证明我们不能再用b的值了,因为f[j]+sum[i]-sum[j]大

    所以在以后的过程中sum[i]只会越来越大,所以我们把sum1中j弹去加入sum2中

    细节:

    1.注意j<i-k的情况要处理两遍

    2.关于堆内无值的情况要随时特判

            if(sum1.size())min1_id=sum1.top().second;
            if(sum2.size())min2_id=sum2.top().second;
            while(!sum1.empty()&&f[min1_id]-sum[min1_id]+sum[i]>f[min1_id]+b[min1_id])
            {
               sum1.pop();          
               sum2.push(make_pair(-(f[min1_id]-sum[min1_id]),min1_id));  
               min1_id=0;
               if(sum1.size())min1_id=sum1.top().second;
            }

    这里一开始没有特判是否为空死了很久........

     1 #include<bits/stdc++.h>
     2 #define int long long
     3 #define MAXN 1010000
     4 using namespace std;
     5 priority_queue<pair<int,int> >sum1;
     6 priority_queue<pair<int,int> >sum2;
     7 int n,k;
     8 int f[MAXN];
     9 int a[MAXN],b[MAXN],sum[MAXN];
    10 int min1_id=0,min2_id=0;
    11 void clear(int i)
    12 {
    13       while(sum1.size()&&sum1.top().second<i-k)
    14       {
    15              sum1.pop();
    16              min1_id=sum1.top().second;
    17       }
    18       while(sum2.size()&&sum2.top().second<i-k)
    19       {
    20              sum2.pop();
    21              min2_id=sum2.top().second;        
    22       }
    23 }     
    24 int top[50];
    25 void find_duilie()
    26 {
    27      while(!sum1.empty())
    28      {     
    29           top[++top[0]]=sum1.top().second;         
    30           sum1.pop();
    31      }
    32      for(int i=1;i<=top[0];++i)
    33      sum1.push(make_pair(-(f[top[i]]-sum[top[i]]),top[i])),top[i]=0;
    34      top[0]=0;
    35 }
    36 signed main()
    37 {
    38   // freopen("text.in","r",stdin);
    39   // freopen("wa.out","w",stdout);
    40     scanf("%lld%lld",&n,&k);
    41     for(int i=1;i<=n;++i)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
    42     for(int i=0;i<n;++i)
    43     {
    44         scanf("%lld",&b[i]);
    45     }
    46     memset(f,0x3f3f3f,sizeof(f));
    47     f[0]=0;
    48     sum1.push(make_pair(-b[0],0));
    49     for(int i=1;i<=n;++i)
    50     {
    51         min1_id=0;min2_id=0;
    52         if(sum1.size())
    53         {
    54            min1_id=sum1.top().second;
    55         }
    56         if(sum2.size())
    57         {
    58            min2_id=sum2.top().second;
    59         }
    60         clear(i);
    61         if(sum1.size())min1_id=sum1.top().second;
    62         if(sum2.size())min2_id=sum2.top().second;
    63         while(!sum1.empty()&&f[min1_id]-sum[min1_id]+sum[i]>f[min1_id]+b[min1_id])
    64         {
    65            sum1.pop();          
    66            sum2.push(make_pair(-(f[min1_id]-sum[min1_id]),min1_id));  
    67            min1_id=0;
    68            if(sum1.size())min1_id=sum1.top().second;
    69         }
    70         clear(i);     
    71         if(sum1.size())min1_id=sum1.top().second;
    72         if(sum2.size())min2_id=sum2.top().second; 
    73         if(!sum1.size())
    74         {
    75              f[i]=f[min2_id]-sum[min2_id]+sum[i];
    76         }
    77         else if(!sum2.size())
    78         {
    79              f[i]=f[min1_id]+b[min1_id];
    80         }
    81         else
    82         {
    83              f[i]=min(f[min1_id]+b[min1_id],f[min2_id]-sum[min2_id]+sum[i]);
    84         }
    85         sum1.push(make_pair(-(f[i]+b[i]),i));
    86     }
    87     printf("%lld
    ",f[n]);
    88 }
    View Code

     调不过只好打对拍啦啦啦........

    随机数据生成

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int random(int m)
     4 {
     5     return (long long)rand()*rand()%m;
     6 }
     7 int main()
     8 {
     9     freopen("text.in","w",stdout);
    10     srand((unsigned)time(0));
    11     int n=1000;
    12     int m=random(n)+1;
    13     printf("%d %d
    ",n,m);
    14     for(int i=1;i<=n;++i)
    15     {
    16         printf("%d ",random(100)+1);
    17     }
    18     cout<<endl;
    19     for(int i=1;i<=n;++i)
    20     {
    21         printf("%d ",random(100)+1);
    22     }
    23     return 0;
    24 }
    View Code

    以及对拍

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main()
     4 { 
     5     int c=0;
     6     while(true)
     7     {
     8          system("./pai");
     9          system("./ac");
    10          system("./wa");
    11          if(system("diff -b -B ac.out wa.out"))
    12          {
    13             puts("WA");
    14             return 0;
    15          }
    16          cout<<++c<<" ";
    17          puts("AC");
    18     }
    19     return 0;
    20 }
    21 /*
    22 g++ pai.cpp -o pai 
    23 ./pai
    24 g++ ac.cpp -o ac
    25 ./ac
    26 g++ wa.cpp -o wa
    27 ./wa
    28 g++ ran.cpp -o ran
    29 ./ran
    30 */
    View Code
  • 相关阅读:
    Codeforces ECR 83 C. Adding Powers (位运算)
    Codeforces Round #636div3 D. Constant Palindrome Sum (划分区间,差分)
    Codeforces Round #603 C. Everyone is a Winner!
    Centos7 下搭建SVN + Apache 服务器 风行天下
    完整部署CentOS7.2+OpenStack+kvm 云平台环境(1)基础环境搭建 风行天下
    云计算的理解 风行天下
    Python之路3【知识点】白话Python编码和文件操作 风行天下
    C#中TreeView组件使用方法初步
    复制文件时explorer.exe出错解决方法
    C# 里TreeView绑定数据库实现分类
  • 原文地址:https://www.cnblogs.com/Wwb123/p/11379094.html
Copyright © 2020-2023  润新知