「模拟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\n",*it);
24      int gg=abs(*it-x);
25      if(s.size()==2)gcdd=gg;
26      //printf("gg=%lld gcd=%lld\n",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\n",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\n",a[i],i,ans);
75                }             
76             }
77             //printf("ans=%lld\n",ans);
78         }
79     }
80     printf("%lld\n",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\n",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",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

 

posted @ 2019-08-19 19:21  Wwb_star  阅读(174)  评论(0编辑  收藏  举报