【蒟蒻】NOIP的各种
好久不见,那啥在做一些可能很**的联赛题哎。。。怪我?
NOIP2014 DAY1 T3 飞扬的小鸟
唔,其实比赛的时候想到了标算,但至今不知道当时怎么死在了75分
然而重新写一遍就A了是smg!!!(咆哮
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #define INF 0x7fffffff #define NN 10010 #define MM 1010 using namespace std; int n,m,k,tot,ans,p; int x[NN],y[NN],l[NN],r[NN],dp[NN][MM]; bool f[NN][MM],ff,fl[NN]; int main() { scanf("%d%d%d",&n,&m,&k); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(fl,0,sizeof(fl)); for (int i=1;i<=n;++i) { scanf("%d%d",&x[i],&y[i]); } for (int i=1;i<=k;++i) { scanf("%d",&p); scanf("%d%d",&l[p],&r[p]); fl[p]=1; } memset(f,0,sizeof(f)); memset(dp,0x3f,sizeof(dp)); tot=0; for (int i=1;i<=m;++i) f[0][i]=1,dp[0][i]=0; for (int i=1;i<=n;++i) { for (int j=x[i]+1;j<=m;++j) if (f[i-1][j-x[i]]) f[i][j]=1,dp[i][j]=min(dp[i][j],dp[i-1][j-x[i]]+1); for (int j=x[i]+1;j<=m;++j) if (f[i][j-x[i]]) f[i][j]=1,dp[i][j]=min(dp[i][j],dp[i][j-x[i]]+1); for (int j=1;j<=m-y[i];++j) if (f[i-1][j+y[i]]) f[i][j]=1,dp[i][j]=min(dp[i][j],dp[i-1][j+y[i]]); for (int j=m-x[i]+1;j<=m;++j) { if (f[i-1][j]) dp[i][m]=min(dp[i][m],dp[i-1][j]+1),f[i][m]=1; if (f[i][j]) dp[i][m]=min(dp[i][m],dp[i][j]+1),f[i][m]=1; } if (fl[i]) { for (int j=1;j<=l[i];++j) f[i][j]=0; for (int j=r[i];j<=m;++j) f[i][j]=0; } ff=0; for (int j=1;j<=m;++j) if (f[i][j]) { ff=1; break;} if (!ff) { puts("0"); printf("%d\n",tot); return 0; } else if (fl[i]) tot++; } ans=INF; for (int i=1;i<=m;++i) if (f[n][i]) ans=min(ans,dp[n][i]); puts("1"); printf("%d\n",ans); return 0; }
NOIP2013 DAY1 T3 货车运输
冰茶几+LCA+DFS+乱搞什么的肯定能做出
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; struct REC {int x,y,v;}; REC a[50010]; int head[20010],ne[20010],u[20010],w[20010],father[20010],fa[10010][20],dis[10010][20],deep[10010]; bool used[10010]; int n,m,xx,yy,total,tot,q,qx,qy; void Insert(int xx,int yy,int zz) { ne[++total]=head[xx]; head[xx]=total; u[total]=yy; w[total]=zz; ne[++total]=head[yy]; head[yy]=total; u[total]=xx; w[total]=zz; } int find_father(int xx) { return father[xx]==xx?xx:father[xx]=find_father(father[xx]); } bool cmp(const REC xx,const REC yy) { return xx.v>yy.v; } void DFS(int xx) { used[xx]=1; for (int i=1;i<=16;++i) { if (deep[xx]<(1<<i)) break; fa[xx][i]=fa[fa[xx][i-1]][i-1]; dis[xx][i]=min(dis[xx][i-1],dis[fa[xx][i-1]][i-1]); } for (int i=head[xx];i;i=ne[i]) { if (used[u[i]]) continue; fa[u[i]][0]=xx; dis[u[i]][0]=w[i]; deep[u[i]]=deep[xx]+1; DFS(u[i]); } return; } int LCA(int xx,int yy) { if (deep[xx]<deep[yy]) swap(xx,yy); int tmp=deep[xx]-deep[yy]; for (int i=0;i<=16;++i) if ((1<<i)&tmp) xx=fa[xx][i]; for (int i=16;i>=0;--i) if (fa[xx][i]!=fa[yy][i]) { xx=fa[xx][i]; yy=fa[yy][i]; } if (xx==yy) return xx; return fa[xx][0]; } int ASK(int xx,int yy) { int minn=0x7fffffff; int tmp=deep[xx]-deep[yy]; for (int i=0;i<=16;++i) { if (tmp&(1<<i)) { minn=min(minn,dis[xx][i]); xx=fa[xx][i]; } } return minn; } int main() { memset(dis,127/3,sizeof(dis)); scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) father[i]=i; for (int i=1;i<=m;++i) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v); sort(a+1,a+1+m,cmp); total=0; for (int i=1;i<=m;++i) { int xx=find_father(a[i].x),yy=find_father(a[i].y); if (xx!=yy) { father[xx]=yy; Insert(a[i].x,a[i].y,a[i].v); ++tot; if (tot==n-1) break; } } for (int i=1;i<=n;++i) if (!used[i]) DFS(i); scanf("%d",&q); for (int i=1;i<=q;++i) { scanf("%d%d",&qx,&qy); if (find_father(qx)!=find_father(qy)) puts("-1"); else { int tmp=LCA(qx,qy); printf("%d\n",min(ASK(qx,tmp),ASK(qy,tmp))); } } return 0; }
NOIP2013 DAY2 T1 同余方程
数学题,%%%Scarlet数论大神
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #define LL long long using namespace std; LL a,b,x,y,ans; LL GCD(LL a,LL b,LL &xx,LL &yy) { if (!b) { xx=1; yy=0; return a; } else { LL sum=GCD(b,a%b,xx,yy); LL tmp=xx; xx=yy; yy=tmp-(a/b)*yy; return sum; } } int main() { scanf("%lld%lld",&a,&b); LL tmp=GCD(a,b,x,y); ans=x%b; while (x<0) x+=b; printf("%lld\n",x); return 0; }
NOIP2013 DAY2 T2 花匠
DP一眼题,然后想着把O(n^2)弄到O(n)就可以了
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #define NN 100100 using namespace std; int f[NN][3],a[NN]; int n; int main() { scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d",&a[i]); f[1][0]=f[1][1]=1; for (int i=1;i<n;++i) { if (a[i]>a[i+1]) { f[i+1][0]=f[i][0]; f[i+1][1]=max(f[i][1],f[i][0]+1); } else if (a[i]<a[i+1]) { f[i+1][1]=f[i][1]; f[i+1][0]=max(f[i][1]+1,f[i][0]); } else { f[i+1][1]=f[i][1]; f[i+1][0]=f[i][0]; } } printf("%d\n",max(f[n][1],f[n][0])); return 0; }
NOIP2012 DAY1 T3 开车旅行
嗯,就是倍增
先用set预处理出每个城市的最近与次近
然后令g[i][j]为从i点走2^j个轮回(注意是轮回,不是步)后的位置,f[i][j][0]为从i点走2^j个轮回后A走过的距离,f[i][j][1]为从i点走2^j个轮回后B走过的距离。
那么很容易推出:
g[i][j]=g[g[i][j-1]][j-1];
f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
f[i][j][1]=f[i][j-1][0]+f[g[i][j-1]][j-1][1];
然后我会告诉你这样就好了哒?
#include <iostream> #include <cstdio> #include <set> #include <cstring> #include <cstdlib> #include <cmath> #define LL long long #define NN 100010 using namespace std; struct REC { int h,num; bool operator <(const REC xx) const{ return h<xx.h; } }; REC a[NN]; set <REC> s; set <REC> ::iterator it; LL f[NN][21][2]; int ne[NN][2],dis[NN][2],g[NN][21]; int n,m,x0,s0,ans=0; void Update(REC xx, REC yy) { if (!ne[xx.num][0]) { ne[xx.num][0]=yy.num; dis[xx.num][0]=abs(xx.h-yy.h); } else if (abs(xx.h-yy.h)<dis[xx.num][0] || (abs(xx.h-yy.h)==dis[xx.num][0] && yy.h<a[ne[xx.num][0]].h)) { ne[xx.num][1]=ne[xx.num][0]; dis[xx.num][1]=dis[xx.num][0]; ne[xx.num][0]=yy.num; dis[xx.num][0]=abs(xx.h-yy.h); } else if (abs(xx.h-yy.h)<dis[xx.num][1] || (abs(xx.h-yy.h)==dis[xx.num][1] && yy.h<a[ne[xx.num][1]].h)) ne[xx.num][1]=yy.num,dis[xx.num][1]=abs(xx.h-yy.h); else if (!ne[xx.num][1]) ne[xx.num][1]=yy.num,dis[xx.num][1]=abs(xx.h-yy.h); return ; } void Query(int ss,int xx,LL &disa,LL &disb) { for (int j=20;j>=0;--j) { if (f[ss][j][0]+f[ss][j][1]<=xx && g[ss][j]) { disa+=f[ss][j][0]; disb+=f[ss][j][1]; xx-=(f[ss][j][0]+f[ss][j][1]); ss=g[ss][j]; } } if (ne[ss][1] && dis[ss][1]<=xx) disa+=dis[ss][1]; } int main() { scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d",&a[i].h),a[i].num=i; for (int i=n;i>=1;i--) { s.insert(a[i]); it=s.find(a[i]); if (it!=s.begin()) { it--; Update(a[i],*it); if (it!=s.begin()) { it--; Update(a[i],*it); it++; } it++; } if ((++it)!=s.end()) { Update(a[i],*it); it++; if (it!=s.end()) Update(a[i],*it); it--; } it--; } for (int i=1;i<=n;++i) { g[i][0]=ne[ne[i][1]][0]; f[i][0][0]=dis[i][1]; f[i][0][1]=dis[ne[i][1]][0]; } for (int j=1;j<=20;++j) for (int i=1;i<=n;++i) { g[i][j]=g[g[i][j-1]][j-1]; f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0]; f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1]; } scanf("%d",&x0); LL ansa=1e15,ansb=0; for (int i=1;i<=n;++i) { LL disa=0,disb=0; Query(i,x0,disa,disb); if (disb&&(!ans||ansa*disb>ansb*disa)) { ans=i; ansa=disa,ansb=disb; } } printf("%d\n",ans); scanf("%d",&m); while (m--) { scanf("%d%d",&s0,&x0); LL disa=0,disb=0; Query(s0,x0,disa,disb); printf("%lld %lld\n",disa,disb); } return 0; }
NOIP2012 DAY2 T2 借教室
鬼畜用了二分答案,其实还是8错滴~~~感觉比线段树好写一点哎
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #define NN 1000100 using namespace std; int n,m,l,r,sum; int rr[NN],d[NN],s[NN],t[NN],a[NN]; bool f,ff; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&rr[i]); for (int i=1;i<=m;++i) scanf("%d%d%d",&d[i],&s[i],&t[i]); l=1; r=m+1; f=1; while (l<r) { ff=0; int mid=(l+r)>>1; for (int i=l;i<=mid;++i) { a[s[i]]+=d[i]; a[t[i]+1]-=d[i]; } sum=0; for (int i=1;i<=n;++i) { sum+=a[i]; if (sum>rr[i]) { f=0; ff=1; break; } } if (ff) { r=mid; for (int i=l;i<=mid;++i) { a[s[i]]-=d[i]; a[t[i]+1]+=d[i]; } } else l=mid+1; } if (f) puts("0"); else { puts("-1"); printf("%d\n",l); } return 0; }
NOIP2012 DAY2 T3 疫情控制
呀,noip膜你赛竟然考真·noip题,不过不然不会这么早去做它了QAQ
二分+贪心判断
先向上移动到首都下一层的几个点,然后某个点有好几个军队的话,就要考虑到首都下一层可能有几个点还是空着的,就是要通过首都移动过去,排序贪心什么的
(↑_↑上面的好混乱)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <queue> #define NN 50010 #define LL long long using namespace std; int head[NN*2],ne[NN*2],u[NN*2],w[NN*2]; bool leaf[NN],tmpp[NN],used[NN]; LL times[NN],diss[NN],dis[NN]; int mark[NN],army[NN],ances[NN],n,m,fa[NN],Q[NN],tmp1[NN],tmp2[NN]; int x,y,z,t,hh,tott; LL r,tot,l; void Build(int x,int y,int z) { ne[++tott] = head[x]; head[x] = tott; u[tott] = y; w[tott] = z; ne[++tott] = head[y]; head[y] = tott; u[tott] = x; w[tott] = z; } bool cmp1(const int xx,const int yy) { return diss[xx]<diss[yy]; } bool cmp2(const int xx,const int yy) { return dis[army[xx]]>dis[army[yy]]; } bool Check(LL mid) { memset(times,-1,sizeof(times)); memset(used,0,sizeof(used)); memcpy(tmpp,leaf,sizeof(tmpp)); for (int i=n;i>=1;--i) { int h=Q[i]; if (mark[h]&&dis[h]>mid) times[h]=mid; times[fa[h]]=max(times[fa[h]],times[h]-diss[h]); if (times[h]>=0) tmpp[h]=1; if (!tmpp[h]) tmpp[fa[h]]=0; } for (int i=1;i<=m;++i) if (dis[army[i]]<=mid) used[i]=1; tmp1[0]=tmp2[0]=0; for (int i=head[1];i;i=ne[i]) if (!tmpp[u[i]]) tmp1[++tmp1[0]]=u[i]; for (int i=1;i<=m;++i) if (used[i]) tmp2[++tmp2[0]]=i; sort(tmp1+1,tmp1+1+tmp1[0],cmp1); sort(tmp2+1,tmp2+1+tmp2[0],cmp2); int jj=1; for (int i=1;i<=tmp2[0];++i) { if (!tmpp[ances[army[tmp2[i]]]]) tmpp[ances[army[tmp2[i]]]]=1; else if (diss[tmp1[jj]]+dis[army[tmp2[i]]]<=mid) tmpp[tmp1[jj]]=1; while (jj<=tmp1[0] && tmpp[tmp1[jj]]) jj++; if (jj>tmp1[0]) return 1; } return 0; } queue <int> que; void BFS(int xx) { hh=1; t=0; Q[++t]=xx; while (hh<=t) { int h=Q[hh++]; leaf[h]=0; for (int i=head[h];i;i=ne[i]) { int v=u[i]; if (v==fa[h]) continue; fa[v]=h; dis[v]=dis[h]+w[i]; diss[v]=w[i]; if (h!=xx) ances[v]=ances[h]; else ances[v]=v; leaf[h]=1; Q[++t]=v; } } } int main() { scanf("%d",&n); tott = 0; tot=1; for (int i=1;i<n;++i) { scanf("%d%d%d",&x,&y,&z); Build(x,y,z); tot+=(LL)z; } scanf("%d",&m); memset(mark,0,sizeof(mark)); for (int i=1;i<=m;++i) scanf("%d",&army[i]),mark[army[i]]=1; BFS(1); l=0; r=tot; while (l<r-1) { LL mid=(l+r)>>1; if (Check(mid)) r=mid; else l=mid; } if (r==tot) puts("-1"); else printf("%lld\n",r); return 0; }
NOIP2011 DAY1 T2 选择客栈
题目: http://codevs.cn/problem/1135/
这真是斯波题啊,O(nk)乱搞表示毫无压力
就是倒着处理一遍,然后正着摞一遍
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #define NN 200010 using namespace std; int n,k,p; int a[NN],b[NN],po[NN],f[NN][55]; long long ans; int main() { scanf("%d%d%d",&n,&k,&p); for (int i=1;i<=n;++i) scanf("%d%d",&a[i],&b[i]); memset(f,0,sizeof(f)); po[n+1]=n+1; for (int i=n;i>=1;--i) { if (b[i]<=p) po[i]=i; else po[i]=po[i+1]; for (int j=0;j<k;++j) f[i][j]=f[i+1][j]; f[i][a[i]]++; } ans=0; for (int i=1;i<=n;++i) { if (po[i]!=i) { ans+=f[po[i]][a[i]]; } if (po[i]==i) { ans+=f[i+1][a[i]]; } } printf("%lld\n",ans); return 0; }
NOIP2011 DAY2 T1 计算系数
其实就是C(k,n)*a^n*b*m就好了
然后求C(k,n)的时候其实挺简单的啊。。。(逆元其实挺好玩的辣)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #define mod 10007 using namespace std; long long ans; int a,b,k,n,m; long long ny[1010]; long long ksm(int xx,int yy) { long long tmp=1,x=xx; while (yy) { if (yy&1) tmp=tmp*x%mod; yy>>=1; x=x*x%mod; } return tmp; } int main() { scanf("%d%d%d%d%d",&a,&b,&k,&n,&m); ans=1; for (int i=1;i<=k;++i) ny[i]=ksm(i,mod-2); for (int i=k;i>=(k-n+1);--i) ans=(ans*i)%mod; for (int i=1;i<=n;++i) ans=(ans*ny[i])%mod; ans=(ans*ksm(a,n)%mod)*ksm(b,m)%mod; printf("%lld\n",ans); return 0; }
NOIP2010 T3 关押罪犯
并查集水题
排序的时候n和m打反了,调了老久都没调出,感觉可以自爆了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define NN 20010 #define MM 100010 using namespace std; struct REC { int x,y,w; }; int father[NN],e[NN]; REC a[MM]; int n,m; bool cmp(const REC xx,const REC yy) { return xx.w>yy.w; } int find_father(int xx) { if (father[xx]==xx) return xx; int fx=father[xx]; father[xx]=find_father(fx); return father[xx]; } void doing(int xx,int yy) { int xa=find_father(xx),ya=find_father(yy); father[xa]=ya; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;++i) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w); for (int i=1;i<=n;++i) father[i]=i; memset(e,0,sizeof(e)); sort(a+1,a+1+m,cmp); for (int i=1;i<=m;++i) { int xa=find_father(a[i].x),ya=find_father(a[i].y); if (xa==ya) { printf("%d\n",a[i].w); return 0; } if (e[a[i].x]==0 && e[a[i].y]==0){ e[a[i].x]=a[i].y; e[a[i].y]=a[i].x; continue;} if (e[a[i].x]==0) e[a[i].x]=a[i].y; if (e[a[i].y]==0) e[a[i].y]=a[i].x; doing(e[a[i].x],a[i].y); doing(e[a[i].y],a[i].x); } puts("0"); return 0; }
NOIP2008 T4 双栈排序
DFS染色一下什么的,然后就乱搞
#include <cstdio> #include <iostream> #include <cmath> #include <cstring> #include <stack> #define NN 1010 using namespace std; stack<int> stacka,stackb; bool ff; int f[NN],a[NN],colour[NN]; bool e[NN][NN]; int n,k; void work(int xx,int yy) { colour[xx]=yy; for (int i=1;i<=n;++i) if (e[xx][i]) { if (yy==colour[i]) { ff=1; return; } if (colour[i]==0) work(i,3-yy); if (ff) return; } } int main() { scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d",&a[i]); f[n+1]=0x7fffffff; for (int i=n;i>=1;--i) f[i]=min(a[i],f[i+1]); for (int i=1;i<=n;++i) for (int j=i+1;j<=n;++j) { if (a[i]<a[j] && f[j+1]<a[i]) e[i][j]=e[j][i]=1; } memset(colour,0,sizeof(colour)); ff=0; for (int i=1;i<=n;++i) if (colour[i]==0) work(i,1); if (ff) { puts("0"); return 0; } k=1; for (int i=1;i<=n;++i) { if (colour[i]==1) { stacka.push(a[i]); printf("a "); } else { stackb.push(a[i]); printf("c "); } while (((!stacka.empty())&&stacka.top()==k) || ((!stackb.empty())&&stackb.top()==k)) { if ((!stacka.empty())&&stacka.top()==k) { printf("b "); stacka.pop(); } else { printf("d "); stackb.pop(); } k++; } } puts(""); return 0; }
(感觉好像未完待续。。。)