终于回来整理了,这两场比赛我也是醉了,第一场-1分,第二场被skip,还是太菜啊qaq
T1T2过水忽略直接看后面
T3大意:给你一个长度为n的序列a1,a2,a3···an,你需要把这些数分成若干组,使得每组数任意两数之差严格大于d,并且满足组数尽可能少。
sol:有理有据的贪心。开一个小根堆,存入每一组的最大的数,当有一个新的数字时,判断它是否大于堆顶的元素+d,若满足就把当前元素归入哪一组并更新小根堆,否则新开一个编号,压入堆中。
#include <queue> #include <cstdio> #include <algorithm> using namespace std; const int N=200005; struct data{int p,q;}a[N]; inline bool cmp(data a,data b){return a.p<b.p;} struct node{int num,id;}; priority_queue<node>q; inline bool operator<(const node &p,const node &q){return p.num>q.num;} int n,m,d,re=0,b[N]; int main() { int i; scanf("%d%d%d",&n,&m,&d); for(i=1;i<=n;i++)scanf("%d",&a[i].p),a[i].q=i; sort(a+1,a+n+1,cmp); re=1; q.push((node){a[1].p,1}); b[a[1].q]=1; for(i=2;i<=n;i++) { node tmp=q.top(); if(tmp.num+d<a[i].p) { q.pop(); q.push((node){a[i].p,tmp.id}); b[a[i].q]=tmp.id; } else { re++; q.push((node){a[i].p,re}); b[a[i].q]=re; } }printf("%d ",re); for(i=1;i<n;i++)printf("%d ",b[i]); printf("%d",b[n]); }
T4大意:你当前高度为h,你每往前飞一个单位就会下降一个单位(不能贴地飞行),给出n段气流,在气流中你不会下降,求你可以飞的最远距离(不限制起点)ps:气流从左到右有序给出。
sol:先对1~n段气流做一个前缀和,记录1~i段会下降的距离和会向前滑行的距离,易知起点一定是某段气流的左端点(不然开始就白白下降),所以枚举左端点,二分右端点最远可能的位置,得到答案。
#include <cstdio> #include <algorithm> using namespace std; const int N=200005; #define int long long int n,h,ans=0,s[N],su[N]; struct node{int x,y;}a[N]; inline bool jud(int S,int T) { if(s[T]-s[S]<h)return true; else return false; } signed main() { int i,l,r,mid,tmp; scanf("%lld%lld",&n,&h); for(i=1;i<=n;i++)scanf("%lld%lld",&a[i].x,&a[i].y),ans=max(ans,a[i].y-a[i].x+h); for(i=2;i<=n;i++)s[i]=s[i-1]+a[i].x-a[i-1].y; for(i=1;i<=n;i++)su[i]=su[i-1]+a[i].y-a[i].x; for(i=1;i<=n;i++) { l=i,r=n,mid,tmp; while(l<=r) { mid=(l+r)/2; if(jud(i,mid))l=mid+1,tmp=mid;else r=mid-1; }ans=max(ans,su[tmp]-su[i-1]+h); }printf("%lld ",ans); }
T5大意:有一棵树,现在给你每条树边被去掉时,形成的两个联通块中点的最大的编号分别是多少,问满足条件的树存不存在,若存在请构造出这棵树
sol:每条边一定有一端的最大值为n,所以我们就围着n建菊花图就好了,左右两端最大值相同的边就串成一条链接在n上
#include <cstdio> #include <vector> #include <cstring> using namespace std; const int N=1005; int n,in1[N],a[N],b[N],n1=0,n2=0; bool G[N][N]; vector<int>V[N]; int main() { int i,j,x,y,bo=0; scanf("%d",&n); memset(in1,0,sizeof in1); for(i=1;i<n;i++) { scanf("%d%d",&x,&y); if(y!=n)return 0*printf("NO "); in1[x]++; } for(i=1;i<n;i++)if(!in1[i])a[++n1]=i;else b[++n2]=i; for(i=1,j=1;i<=n2;i++) { if(in1[b[i]]>1) { in1[b[i]]--; while(in1[b[i]]>0&&j<=n1) { if(b[i]<a[j]){bo=1;break;} V[b[i]].push_back(a[j]); in1[b[i]]--; j++; }if(bo)break; }else G[b[i]][n]=1; } if(!bo) { for(i=1;i<n;i++) { if(V[i].size()) { for(j=0;j<V[i].size()-1;j++) { G[V[i][j]][V[i][j+1]]=1; }G[i][V[i][0]]=1; G[V[i][V[i].size()-1]][n]=1; } }printf("YES "); for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(G[i][j])printf("%d %d ",i,j); }else return 0*printf("NO "); }
T3大意:给出一个长度为n的序列,每次可以合并两个数ax,ay(ax会消失,ay变成ax*ay),你还有一个机会可以删除一个数,使得最后得到的数最大
sol:大力高精 想都别想 于是乎发现:如果负数有奇数个,那么要删除绝对值最小的那个,如果有0的话,先把0合成一个,以上两样如都有,则合在一起去掉反之则去掉存在的那个,(与此同时要注意,如果只剩一个数,是万万不能删掉的,不要问为什么,全删了答案是什么qaq)
#include <cstdio> #include <algorithm> using namespace std; const int N=200005; int n,m,a[N],cnt=0,v[N]; int main() { int i,j,po=0,bo=0; scanf("%d",&n); m=n; for(i=1;i<=n;i++)scanf("%d",&a[i]); if(n==1)return 0; for(i=1;i<=n;i++) { if(a[i]<0) {bo++; if(!po)po=i; else if(a[po]<a[i])po=i;} else if(a[i]==0)v[++cnt]=i; }i=1; while(i<cnt) { printf("1 %d %d ",v[i],v[i+1]); i++; m--; if(m==1) return 0; } if(bo&1) { if(cnt) { printf("1 %d %d ",min(po,v[cnt]),max(po,v[cnt])); m--; if(m!=1)printf("2 %d ",max(po,v[cnt])); else return 0; } else { printf("2 %d ",po); }j=0; for(i=1;i<=n&&j<=n;) { while((a[i]==0||i==po)&&i<=n)i++; j=i+1; while((a[j]==0||j==po)&&j<=n)j++; if(j>n)return 0; printf("1 %d %d ",i,j); i=j; j=i+1; m--; if(m==1)return 0; } } else { po=0; if(cnt) { printf("2 %d ",v[cnt]); }j=0; for(i=1;i<=n&&j<=n;) { while((a[i]==0||i==po)&&i<=n)i++; j=i+1; while((a[j]==0||j==po)&&j<=n)j++; if(j>n)return 0; printf("1 %d %d ",i,j); i=j; j=i+1; m--; if(m==1)return 0; } } }
T4大意:给出一个长度为n的序列和一个数d,找出所有连续的子串使得其和小于d,求子串个数
sol:树状数组加二分,先计算前缀和,离散一下,从1~n枚举每个前缀和,统计比s[i]-d大的个数,最后算一下有几个前缀和小于d,加入答案就完了,似乎比T3要水
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long const int N=200005; int n,m,t,tot=0,s[N],tr[N],pre[N]; struct node{int w,id,nid;}a[N]; inline bool cmp(node a,node b){return a.w<b.w;} inline bool cmp1(node a,node b){return a.id<b.id;} #define lowbit(x) ((x)&(-x)) inline void ins(int x){while(x>0){tr[x]++;x-=lowbit(x);}} inline int que(int x){int re=0;while(x<=tot){re+=tr[x];x+=lowbit(x);}return re;} inline int ask(int v) { int l=1,r=tot+1,mid,tmp=tot+1; while(l<=r) { mid=(l+r)>>1;if(pre[mid]>=v)r=mid-1,tmp=mid;else l=mid+1; }if(pre[tmp]==v)return tmp+1;else return tmp; } signed main() { int i,x,ans=0,po; scanf("%lld%lld",&n,&t); for(i=1;i<=n;i++) { scanf("%lld",&x); s[i]=s[i-1]+x; a[i].w=s[i]; a[i].id=i; }sort(a+1,a+n+1,cmp); tot=1; pre[1]=a[1].w; a[1].nid=1; for(i=2;i<=n;i++) { if(a[i].w!=a[i-1].w){tot++;pre[tot]=a[i].w;} a[i].nid=tot; }sort(a+1,a+n+1,cmp1); for(i=1;i<=n;i++) { po=ask(pre[a[i].nid]-t); ans+=que(po); ins(a[i].nid); } for(i=1;i<=n;i++)if(s[i]<t)ans++; printf("%lld ",ans); }