「训练日志 20」 6.19 差距

这次考试题解好像都写在题面上了。。

贪婪。

离。

堆积。

T1 嚎叫响彻在贪婪的厂房

  等差序列,要保证第i位与第i-1位的差值与之前的所有集合中的数中任意两个相邻数的差值gcd不为1,还有序列中没有重复元素。

  考试的时候想的是分解质因数,然后崩了,又难想又难打。

  其实思路挺简单,实现的话用一个$map$$/$$set$$/$$hash$判重搞定然后没什么了。

  为什么没想到$gcd$呢?还是考试把自己搞死了,自己没想到这一点,只想这分解,最后也没有码出来。

  多方向找性质,不要受局限。

  小弟不才。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<map>
 4 #include<limits>
 5 #define LL long long 
 6 #define HZOI std
 7 using namespace HZOI;
 8 const int HASH=19260817;
 9 const int Hash=233;
10 const int N=1e7+3;
11 LL n,cnt,lst,ans,gcd;
12 LL a[N];
13 unsigned LL hs[HASH+3];
14 map<LL ,bool > mp;
15 inline void Add(LL ,int );
16 inline LL Ask(LL );
17 LL Gcd(LL ,LL );
18 inline LL read();
19 inline LL max(LL a,LL b) {return a>b?a:b;}
20 inline LL min(LL a,LL b) {return a<b?a:b;}
21 inline LL _abs(LL a) {return a<0?-a:a;}
22 int main()
23 {
24     n=read();
25     for (int i=1; i<=n; ++i) a[i]=read();
26     Add(a[1],1),cnt=lst=1;
27     for (int i=2; i<=n; ++i)
28     {
29         if (cnt==1)
30         {
31             if (a[i]==a[i-1]) {lst=i;++ans;continue;}
32             ++cnt,Add(a[i],1);
33             gcd=_abs(a[i]-a[i-1]);
34             if (gcd==1)
35             {
36                 Add(a[i-1],-1);
37                 ++ans; lst=i; cnt=1;
38             }
39             continue;
40         }
41         if (Ask(a[i])) 
42         {
43             ++ans;
44             for (int j=lst; j<i; ++j) Add(a[j],-1);
45             lst=i, cnt=1, Add(a[i],1);
46             continue;
47         }
48         LL negcd=Gcd(gcd,_abs(a[i]-a[i-1]));
49         if (negcd<=1)
50         {
51             ++ans;
52             for (int j=lst; j<i; ++j) Add(a[j],-1);
53             lst=i, cnt=1, Add(a[i],1);
54             continue;
55         }
56         gcd=Gcd(gcd,negcd);
57         Add(a[i],1),++cnt;
58     }
59     printf("%lld\n",ans+1);
60 }
61 LL Gcd(LL a,LL b)
62 {
63     if (!b) return a;
64     return Gcd(b,a%b);
65 }
66 inline void Add(LL x,int data)
67 {
68     unsigned LL num=x*Hash*Hash*Hash*Hash;
69     num%=HASH;
70     hs[num]+=data;
71 }
72 inline LL Ask(LL x)
73 {
74     unsigned LL num=x*Hash*Hash*Hash*Hash;
75     num%=HASH;
76     if (hs[num]>0) return 1;
77     return 0;
78 }
79 inline LL read()
80 {
81     LL nn=0; char cc=getchar();
82     while (cc<'0' || cc>'9') cc=getchar();
83     while (cc>='0' && cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar();
84     return nn;
85 }
嚎叫响彻在贪婪的厂房(hash,用map直接替掉hash即可)

 

T2 主仆见证了 Hobo 的离别

  咋说呢这题。。

  考试的时候做了个笔记:动态开点权值线段树+树上合并。

  然后我死了。

  “正解”很简单,直接在线算,每次跑一遍Dfs暴力查找两个元素是否在同一条链上,居然能AC跑的还飞快。

  其实真正的正解是离线算法,但我不会,只好水过了。

  不得不说数据太水了。

  小弟不才。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define HZOI std
 4 using namespace HZOI;
 5 const int N=5e6+3;
 6 int n,m;
 7 int dfn[N<<2],low[N<<2];
 8 int tt,first[N<<2],vv[N<<3],nx[N<<3];
 9 int Dfs(int ,int ,int );
10 inline void Add(int ,int );
11 inline int read();
12 int main()
13 {
14     n=read(),m=read();
15     for (int i=1,opt,a,b,c,d; i<=m; ++i)
16     {
17         opt=read(),a=read(),b=read();
18         if (!opt)
19         {
20             ++n;
21             if (b==1) { int x=read(); Add(x,n), Add(n,x); continue;}
22             if (!a) for (int i=1,x; i<=b; ++i) Add(n,read());
23             else for (int i=1,x; i<=b; ++i) Add(read(),n);
24         }
25         if (opt)
26         {
27             if (Dfs(a,0,b)) puts("1");
28             else puts("0");
29         }
30     }
31 }
32 int Dfs(int k,int father,int goal)
33 {
34     if (k==goal) return 1;
35     for (int i=first[k]; i; i=nx[i])
36     {
37         int ver=vv[i];
38         if (ver==father) continue;
39         if (Dfs(ver,k,goal)) return 1;
40     }
41     return 0;
42 }
43 inline void Add(int u,int v)
44 {
45     vv[++tt]=v,nx[tt]=first[u],first[u]=tt;
46 }
47 inline int read()
48 {
49     int nn=0; char cc=getchar();
50     while (cc<'0' || cc>'9') cc=getchar();
51     while (cc>='0' && cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar();
52     return nn;
53 }
主仆见证了 Hobo 的离别

 

T3 征途堆积出友情的永恒

  这道题就有点水平了。

  dp很好打,$dp_i=min(dp_j+max(b_j,sum_i-sum_j))$

  含义不难理解,考虑优化。

  我们发现$dp_j+b_j$是一个定值,所以我们只要选取其最小的就可以了,而$dp_j-sum_j+sum_i$随$i$单调递增,考虑用既然题目上都说了用堆优化,两个堆,一个维护$dp_i+b_i$,第二个维护$dp_i-sum_i$,然后乱搞就好了。

  堆一的弹出条件:1.堆顶元素花费大于其位置为$sum$的花费 2.堆顶元素在范围内。

  开搞,把堆一中元素弹走后,由二接受,然后就可以了,注意判断可行条件

  小弟不才。

  

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 const int maxn=500005;
 6 #define ll long long
 7 int n,k;
 8 ll  f[maxn],sum[maxn];
 9 int a[maxn],b[maxn];
10 struct Binary_heap{
11     ll top,heap[maxn],pn[maxn];
12     int topp(){  return pn[1];  }
13     void swap(ll &x,ll &y){ x^=y,y^=x,x^=y; }
14     void up(int p){
15         while(p>1){
16             if(heap[p]<heap[p>>1])  swap(heap[p],heap[p>>1]),swap(pn[p],pn[p>>1]);
17             else break;   p>>=1;
18         }
19     }
20     void down(int p){
21         int turn=p<<1;
22         while(turn<=top){
23             if(turn<top&&heap[turn]>heap[turn+1])  ++turn;
24             if(heap[p]>heap[turn]) swap(heap[turn],heap[p]),swap(pn[p],pn[turn]);
25             else break;    p=turn,turn<<=1;
26         }
27     }
28     void insert(ll x,int y){heap[++top]=x; pn[top]=y; up(top); }
29     void pop(){ heap[1]=heap[top]; pn[1]=pn[top--]; down(1); }
30 }fir,sec;
31 inline int read()
32 {    
33     int t=0; char ch=getchar();    
34     while(ch<'0'||ch>'9')  ch=getchar();
35     while(ch>='0'&&ch<='9')  t=(t<<3)+(t<<1)+(ch^48),ch=getchar();
36     return t;
37 }
38 int main()
39 {
40     n=read(),k=read();
41     for(register int i=1;i<=n;++i)  a[i]=read(),sum[i]=sum[i-1]+a[i];
42     for(register int i=0;i<n;++i)  b[i]=read();
43     ll tf,ts,turn;
44     memset(f,0x7f,sizeof(f));
45     f[0]=0;    
46     fir.insert(b[0],0);
47     for(register int i=1;i<=n;++i){
48         turn=max(0,i-k);
49         while(1){
50             if(fir.top) tf=fir.topp(); else tf=-1;
51             if(sec.top) ts=sec.topp();  else ts=-1;
52             while(fir.top&&tf<turn) fir.pop(),tf=fir.topp();
53             while(sec.top&&ts<turn) sec.pop(),ts=sec.topp();
54             if(!fir.top)  tf=-1;  if(!sec.top)  ts=-1;
55             if(ts!=-1&&(tf==-1||f[ts]-sum[ts]+sum[i]<f[tf]+b[tf])){
56                 f[i]=f[ts]-sum[ts]+sum[i]; break;
57             }
58             if(b[tf]>=sum[i]-sum[tf]){ f[i]=f[tf]+b[tf]; break; }
59             while(fir.top&&b[tf]<sum[i]-sum[tf]){  sec.insert(f[tf]-sum[tf],tf),fir.pop(),tf=fir.topp(); }
60         }
61         fir.insert(f[i]+b[i],i);
62     }
63     printf("%lld",f[n]);
64 }
征途堆积出友情的永恒

 

posted @ 2019-08-20 06:32  _LH  阅读(190)  评论(0编辑  收藏  举报