这次考试题解好像都写在题面上了。。
贪婪。
离。
堆积。
T1 嚎叫响彻在贪婪的厂房
等差序列,要保证第i位与第i-1位的差值与之前的所有集合中的数中任意两个相邻数的差值gcd不为1,还有序列中没有重复元素。
考试的时候想的是分解质因数,然后崩了,又难想又难打。
其实思路挺简单,实现的话用一个$map$$/$$set$$/$$hash$判重搞定然后没什么了。
为什么没想到$gcd$呢?还是考试把自己搞死了,自己没想到这一点,只想这分解,最后也没有码出来。
多方向找性质,不要受局限。
小弟不才。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 ",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 }
T2 主仆见证了 Hobo 的离别
咋说呢这题。。
考试的时候做了个笔记:动态开点权值线段树+树上合并。
然后我死了。
“正解”很简单,直接在线算,每次跑一遍Dfs暴力查找两个元素是否在同一条链上,居然能AC跑的还飞快。
其实真正的正解是离线算法,但我不会,只好水过了。
不得不说数据太水了。
小弟不才。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
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.堆顶元素在范围内。
开搞,把堆一中元素弹走后,由二接受,然后就可以了,注意判断可行条件。
小弟不才。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }