noip题目
来源:互联网 发布:mindly mac 编辑:程序博客网 时间:2024/06/08 06:37
题目:选择客栈
题解:
本来写了一个60pts的RMQ,但是发现正解非常的巧妙,f[x]表示i之前(不包括i)颜色为x能用的客栈的数量,c[x]表示离这种颜色最近的客栈位置,cnt[x]表示从开始到i这个位置x的数量是多少,代码简洁思路巧妙。
代码:
#include <cstdio>#include <cmath>#include <iostream>using namespace std;int f[55],c[55],n,k,p,i,cnt[55];int main(){ int ans=0,last=0; scanf("%d%d%d",&n,&k,&p); for (i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); if (y<=p) last=i; if (last>=c[x]) f[x]=cnt[x]; ans+=f[x]; c[x]=i; cnt[x]++; } printf("%d",ans);}
题目:借教室
题解:
运用前缀和我考虑到了,但如果n这样试过去的话很不科学,所以这里运用二分,二分订单k表示订单k不符合条件,而k-1的订单都符合条件,总复杂度O(logn(n+m))
代码:
#include <cstdio>#include <cstring>#define N 1000005using namespace std;struct hh{int d,s,t,id;}dd[N];int tmp[N],n,R[N];bool check(int k){ memset(tmp,0,sizeof(tmp)); for (int i=1;i<=k;i++) { tmp[dd[i].s-1]+=dd[i].d; tmp[dd[i].t]-=dd[i].d; } for (int i=n-1;i>=1;i--) tmp[i]+=tmp[i+1]; for (int i=1;i<=n;i++) if (tmp[i]+R[i]<0) return 0; return 1;}int main(){ int m,i; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) scanf("%d",&R[i]); for (i=1;i<=m;i++) scanf("%d%d%d",&dd[i].d,&dd[i].s,&dd[i].t); int l=1,r=m+1; while (l<r) { int mid=(l+r)>>1; if (check(mid)) l=mid+1; else r=mid; } if (r==m+1) printf("0"); else printf("-1\n%d",r);}
题目:观光公交
题解:
1、我们要在收益人最多的边上加速 2、如果这辆车的到达时间 比 这个景点来的最晚客人时间 要早的话,我们就不算为收益,反正早到了还要等着。
然后是几个数组的设计
代码:
#include <cstdio>#include <iostream>#define N 1005#define M 10005using namespace std;struct ck{int t,a,b;}pas[M];int d[N],t[M],go[N],f[N],getto[N],maxx[N];int main(){ int n,m,i,k,j; scanf("%d%d%d",&n,&m,&k); for (i=1;i<n;i++) scanf("%d",&d[i]); for (i=1;i<=m;i++) { scanf("%d%d%d",&pas[i].t,&pas[i].a,&pas[i].b); maxx[pas[i].a]=max(maxx[pas[i].a],pas[i].t); go[pas[i].b]++; } getto[1]=0; for (i=2;i<=n;i++) getto[i]=max(getto[i-1],maxx[i-1])+d[i-1]; while (k--) { f[n]=0; for (i=n;i>=2;i--) if (!d[i-1]) f[i-1]=0;//不能寻找收益人群 else{ f[i-1]=go[i];//首先这条路对下一站下车的人肯定有意义 if (getto[i]>maxx[i]) f[i-1]+=f[i];//如果修改对后面有益 } int maxn=0,pos; for (i=1;i<=n;i++) if (maxn<f[i]){maxn=f[i]; pos=i;} if (maxn==0) break; d[pos]--; for (i=2;i<=n;i++) getto[i]=max(getto[i-1],maxx[i-1])+d[i-1]; } int ans=0; for (i=1;i<=m;i++) ans+=getto[pas[i].b]-pas[i].t; printf("%d",ans);}
题目:乌龟棋
题解:
1A满意。f[i][j][k][l]表示1剩i张,2剩j张…….
代码:
#include <cstdio>#include <iostream>using namespace std;int f[45][45][45][45],a[360],b[5];int main(){ int n,m,i,j,k,l; scanf("%d%d",&n,&m); for (i=0;i<n;i++) scanf("%d",&a[i]); for (i=1;i<=m;i++) { int a;scanf("%d",&a); b[a]++; } f[b[1]][b[2]][b[3]][b[4]]=a[0]; for (i=b[1];i>=0;i--) for (j=b[2];j>=0;j--) for (k=b[3];k>=0;k--) for (l=b[4];l>=0;l--) { int bu=(b[1]-i)+(b[2]-j)*2+(b[3]-k)*3+(b[4]-l)*4; if (i<b[1]) f[i][j][k][l]=max(f[i][j][k][l],f[i+1][j][k][l]+a[bu]); if (j<b[2]) f[i][j][k][l]=max(f[i][j][k][l],f[i][j+1][k][l]+a[bu]); if (k<b[3]) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k+1][l]+a[bu]); if (l<b[4]) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k][l+1]+a[bu]); } printf("%d",f[0][0][0][0]);}
题目:聪明的质检员
题解:
一上来正解?二分+前缀和~嘛嘛嘛~但是最大值1e9不行啊,一些乱七八糟的元素爆longlong啊,真是烦~
哇改了LL之后一定要改上%lld啊
一个很大的数:0x3f3f3f3f3f3f3f3f
代码:
#include <cstdio>#include <iostream>#include <cstring>#define INF 1e9#define N 200005#define LL long longusing namespace std;struct hh{int l,r;}pe[N];LL s,ww[N];LL jd=0x3f3f3f3f3f3f3f3f;int n,m,w[N],v[N],len[N];bool check(int mid){ int i; for (i=1;i<=n;i++) { ww[i]=ww[i-1]; len[i]=len[i-1]; if (w[i]>=mid) ww[i]+=v[i],len[i]++; } LL ans=0; for (i=1;i<=m;i++) ans+=(len[pe[i].r]-len[pe[i].l-1])*(ww[pe[i].r]-ww[pe[i].l-1]); if (s<ans) { if (ans-s<jd) jd=ans-s; return 1; } else { if (s-ans<jd) jd=s-ans; return 0; } }int main(){ int l=INF,r=0,i; scanf("%d%d%lld",&n,&m,&s); for (i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]),l=min(l,w[i]),r=max(r,w[i]); for (i=1;i<=m;i++) scanf("%d%d",&pe[i].l,&pe[i].r); while (l<r) { int mid=(l+r)>>1; if (check(mid)) l=mid+1; else r=mid-1; } check(l); printf("%lld",jd);}
题目:传染病控制
题意:一棵树每一层砍一条边,求与根连通的最小节点数
题解:
好的每次切掉重儿子是不对滴,请看优美菊花图( 有子树深度为2,一个根,剩下的全都是叶子)
正好学习一下vector的应用?
首先dfs建树找出每个点控制的点的个数和每个点的深度,还有就是深度为dep的点用一个vector存起来。然后以深度为关键字搜索,每一深度枚举要切断的点,将它控制的点的个数计入答案,然后套一个dfs…用来把这个点的所有子节点标记…到时候就不能切断它们了…
其实就是一个特别特别暴力需要强行枚举的题目啊。。。。。
代码:
#include <cstdio>#include <iostream>#include <vector>#define N 700#define INF 1e9using namespace std;int nxt[N],point[N],v[N],tot,son[N],h[N],f[N],maxx,ans=INF;bool vis[N];vector <int> s[N];void addline(int x,int y){ ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void dfs(int x,int fa){ h[x]=h[fa]+1; s[h[x]].push_back(x); son[x]=1; for (int i=point[x];i;i=nxt[i]) if (v[i]!=fa) { dfs(v[i],x); son[x]+=son[v[i]]; }}void bj(int x,bool flag){ vis[x]=flag; for(int i=point[x];i;i=nxt[i]) if(h[v[i]]>h[x]) bj(v[i],flag);}void dfs1(int dep,int now){ ans=min(ans,now); for (int i=0;i<s[dep].size();i++) if (!vis[s[dep][i]]) { bj(s[dep][i],1); dfs1(dep+1,now-son[s[dep][i]]); bj(s[dep][i],0); }}int main(){ int n,p,i,j; scanf("%d%d",&n,&p); for (i=1;i<=p;i++) { int x,y; scanf("%d%d",&x,&y); addline(x,y); } dfs(1,0); dfs1(2,n); printf("%d",ans); }
题目:篝火晚会
题解:
我真的炒鸡炒鸡讨厌CSDN!!!
可以用贪心来做,如果知道原序列和目标序列,算算目标序列中有几个元素和原序列不同,就是答案了。要想办法构造目标序列。可以随便放一个数,然后在它的右边放上一个他希望相邻的数(有两个,所以要分两种情况)然后就可以按照这样的方法逐个构造。
现在构造出了目标序列,但它是个圈,所以要破环成链比较,但这样效率O(n^2),会超时。
其实,只需要知道有多少个元素和原序列相同,就能知道有几个元素不同了。
那么,对于某个目标序列里的元素a[i],如果我们比较的时候从目标序列i-a[i]+1的位置开始,就会和原序列相同,可以f[i-a[i]+1]++;(但要注意边界),然后取所有的n-f[i]的最小值。
代码:
#include <cstdio>#include <iostream>#include <cstring>#define N 50005#define INF 1e9using namespace std;int a[N],b[N],t[N],f[N],ans=INF;int main(){ int n,i; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); for (i=1;i<=n;i++) if (a[a[i]]!=i && b[a[i]]!=i || a[b[i]]!=i && b[b[i]]!=i) {printf("-1"); return 0;} t[1]=1; t[2]=a[1]; for (i=3;i<=n;i++) if (a[t[i-1]]==t[i-2]) t[i]=b[t[i-1]]; else t[i]=a[t[i-1]]; for (i=1;i<=n;i++) if (i-t[i]+1>0) f[i-t[i]+1]++; else f[n+i-t[i]+1]++; for (i=1;i<=n;i++) ans=min(ans,n-f[i]); memset(f,0,sizeof(f)); t[1]=1; t[2]=b[1]; for (i=3;i<=n;i++) if (a[t[i-1]]==t[i-2]) t[i]=b[t[i-1]]; else t[i]=a[t[i-1]]; for (i=1;i<=n;i++) if (i-t[i]+1>0) f[i-t[i]+1]++; else f[n+i-t[i]+1]++; for (i=1;i<=n;i++) ans=min(ans,n-f[i]); printf("%d",ans);}
题目:Hankson 的趣味题
题解:
一看题目就是数论某题
首先画个柿子
可以枚举x为b1的因子,a1的倍数,然后起飞?
代码:
#include <cstdio>using namespace std;int gcd(int a,int b){if (b==0) return a;else return gcd(b,a%b);}int main(){ int T; scanf("%d",&T); while (T--) { int a0,a1,b0,b1,i,ans=0; scanf("%d%d%d%d",&a0,&a1,&b0,&b1); for (i=1;i*i<=b1;i++)//不可以从a1枚举,因为a1*a1大于b1的话不能找到b1所有的因子 if (b1%i==0) { if (i%a1==0 && gcd(i/a1,a0/a1)==1 && gcd(b1/i,b1/b0)==1) ans++; int ly=b1/i; if (ly!=i && ly%a1==0 && gcd(ly/a1,a0/a1)==1 && gcd(b1/ly,b1/b0)==1) ans++; } printf("%d\n",ans); }}
题目:奶牛的锻炼
题解:详见注释。
代码:
#include <cstdio>#include <cstring>#include <iostream>using namespace std;int a[2005],f[2005][505];int main(){ int n,m,i,j; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) scanf("%d",&a[i]); //f[i][j]第i分钟疲倦程度为j的最大距离 memset(f,0x8f,sizeof(f)); f[0][0]=0; for (i=1;i<=n;i++) for (j=0;j<=m;j++) { if (j==0) f[i][j]=max(f[i][j],max(f[i-1][j+1],f[i-1][j]));//上一分钟才开始休息 else { f[i][j]=max(f[i][j],f[i-1][j-1]+a[i]); f[i+j][0]=max(f[i+j][0],f[i-1][j+1]);//上一分钟休息了就休息到底吧 } } printf("%d",f[n][0]);}
题目:新三国争霸
题解:
f[i]表示前i时间最少的花费,总的来说还是比较暴力的题目吧
代码:
#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#define INF 1e9using namespace std;struct road{int x,y,z,id;}sd[5005];int n,m,t,v,k,fa[305],r[305][305],f[55];bool bx[5005][55];int cmp(road a,road b){return a.z<b.z;}int find(int x){ if (fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}int work(int l,int r){ int i,j,cnt=0,len=0; for (i=1;i<=n;i++) fa[i]=i; for (i=1;i<=m;i++) { bool fff=false; for (j=l;j<=r;j++) if (bx[sd[i].id][j]) {fff=true; break;} if (fff) continue; int a=find(sd[i].x),b=find(sd[i].y); if (a!=b){fa[a]=b;cnt++;len+=sd[i].z;if (cnt==n-1) return len;} } return INF;}int main(){ int i,j,p; scanf("%d%d%d%d%d",&n,&m,&t,&v,&k); for (i=1;i<=m;i++) { scanf("%d%d%d",&sd[i].x,&sd[i].y,&sd[i].z); r[sd[i].x][sd[i].y]=r[sd[i].y][sd[i].x]=i; sd[i].id=i; } sort(sd+1,sd+m+1,cmp); scanf("%d",&p); for (i=1;i<=p;i++) { int x,y,t1,t2; scanf("%d%d%d%d",&x,&y,&t1,&t2); int hh=r[x][y]; for (j=t1;j<=t2;j++) bx[hh][j]=true; } memset(f,0x7f,sizeof(f));f[0]=0; for (i=1;i<=t;i++) for (j=0;j<i;j++) f[i]=min(f[i],f[j]+work(j+1,i)*(i-j)*v+k); printf("%d",f[t]);}
to be continued……(luogu的下载次数被我用完了,那我就先放过luogu吧hhhhhh)
- noip题目
- NOIP历年题目分析
- noip题目复习
- NOIP历届题目分类
- 历年noip,apio题目考点
- NOIP题目类型做法总结
- NOIP模拟赛题目以及数据
- NOIP提高组完善程序题目分析
- 【noip题目代码】魔法阵;模拟,iterator,
- 【NOIP考前题目回顾】Luogu P1000
- 【NOIP考前题目回顾】Luogu P1001
- 【NOIP考前题目回顾】Luogu P1003
- 【NOIP考前题目回顾】Luogu P1005
- 【NOIP考前题目回顾】Luogu P1006
- 【NOIP考前题目回顾】Luogu P1005
- 【NOIP考前题目回顾】Luogu P1012
- 【NOIP考前题目回顾】Luogu P1040
- 【NOIP考前题目回顾】Luogu P1046
- 总线驱动模型
- Python基础学习<三>
- MacOS10编译Hadoop2.7.4
- 2017理数全国卷II T21
- poj 2253 Frogger(floyd)
- noip题目
- go语言
- 一个女程序员的默默人生------转正了,不知道该伤心,还是该幸运
- 世界上最简单的病毒(bat)
- PHP应用中利用NoSQL数据库缓存之Memcache
- 树莓派交叉编译
- 操作系统基础知识
- 提高HTML5 canvas性能的几种方法!
- csdn如何转载别人的文章