NOIP2012复赛DAY2
来源:互联网 发布:游戏 建模 软件 编辑:程序博客网 时间:2024/05/22 09:51
NOIP2012——DAY2
1、同余方程
【题目分析】
其实也不用分析了,这道题是作为我们的数论入门题来练的。如果在考场上碰到这种恶心的数学题,不管敲得对敲不对,反正一定要把暴力先敲好。
http://blog.csdn.net/ycdfhhc/article/details/44260687
作为一个蒟蒻,想解释但还是心有余而力不足啊。不懂的小伙伴自行学习,早就懂的小伙伴也可以温习一下。
【代码】
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long longusing namespace std;ll ex_gcd(ll a,ll b,ll &x,ll &y){ ll d=a; if(b){ d=ex_gcd(b,a%b,y,x); y-=a/b*x; }else x=1,y=0; return d;}int main(){ ll a,b,x,y; cin>>a>>b; int ans=ex_gcd(a,b,x,y); while(x<=0)x+=b; cout<<x<<endl; return 0;}
2、借教室
【题目分析】
都DAY2了,还能不能让我愉快地敲一个暴力?
不多说,45分暴力代码先给出。
【45分代码】
#define M 1000005#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;int cnt[M];int main(){ int i,j,n,m; scanf("%d %d",&n,&m); for(i=1;i<=n;i++)scanf("%d",&cnt[i]); for(i=1;i<=m;i++){ int d,l,r; scanf("%d %d %d",&d,&l,&r); for(j=l;j<=r;j++){ cnt[j]-=d; if(cnt[j]<0)break; }if(j!=r+1)break; } if(i==m+1)puts("0"); else puts("-1"),printf("%d\n",i); return 0;}
枚举->贪心,貌似都不行。
我们的目标是完成所有订单。
题目里虽然没有说最大、最小,之类的话,只说了,“如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配”,如果这一份订单如果无法完成,那么我们假设的可以完成所有订单这一目标也一定无法完成。
如果先定一个小目标,看他能不能完成。如果小目标不能完成,大目标也一定不能完成。所以,具有单调性。
思路就变成了二分答案。
同时,在假设当前的目标能够完成的时候,一个一个减太慢了,我们学过差分前缀和(也就是刷漆),将每次查询的复杂度降到了O(n)。
复杂度O(n*logn)。
【代码】
#include<cmath>#include<cstdio>#include<cstring>#include<cstdlib>#define M 1000005#include<iostream>#include<algorithm>using namespace std;void Rd(int &res){ char c;res=0; while(c=getchar(),!isdigit(c)); do{res=(res<<3)+(res<<1)+(c^48);}while(c=getchar(),isdigit(c));}struct quertion{int l,r,d;}q[M];int n,m,ans=0,a[M];long long b[M];bool chk(int x){ bool f=1; long long sum=0; memset(b,0,sizeof(b)); for(int i=1;i<=x;i++){ b[q[i].l]+=q[i].d; b[q[i].r+1]-=q[i].d; } for(int i=1;i<=n;i++){ sum+=b[i]; if(sum>a[i])return 0; }return 1;}int main(){ int i; Rd(n),Rd(m); for(i=1;i<=n;i++)Rd(a[i]); for(i=1;i<=m;i++)Rd(q[i].d),Rd(q[i].l),Rd(q[i].r); int l=1,r=m; while(l<=r){ int mid=l+r>>1; if(!chk(mid))ans=mid,r=mid-1; else l=mid+1; } if(!ans)puts("0"); else printf("-1\n%d\n",ans); return 0;}
天啊撸,刚打好的疫情控制题解没了,都怪一个叫yahong的变态!!
3、疫情控制
【题目分析】
从枚举军队最后的状态入手,可以水到20分。
需要将有限的军队最大的发挥它们的作用,就要不断向上攀爬,使他能满足更多的边疆城市,这是贪心的思想。
从常识中可以知道,若是疫情被能控制,时间越长,更有可能。而我们不可能按照时间的推移来检验该时间是否可行(显然超时),又有“请问最少需要多少个小时才能控制疫情”,得出二分答案的做法。
但是首都的儿子中有些点是本来就没有军队的,所以将军队又分为了需要翻过首都支援的和留在原地的。而我们又希望剩余时间更多的来支援,这还是贪心的思想。
接下来就是如何实现的问题了。
【代码】
#define M 50005#include<queue>#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include<algorithm>#define ll long long#define oo 1e15using namespace std;void Rd(int &res){ res=0;char c; while(c=getchar(),!isdigit(c)); do res=(res<<3)+(res<<1)+(c^48); while(c=getchar(),isdigit(c));}struct node{int v,w,nxt;}st[M<<1];int fa[M],army[M],head[M],rest[M];int n,m,etop=0;bool mk[M];ll dis[M];void add_edge(int u,int v,int w){ st[++etop]=(node){v,w,head[u]},head[u]=etop; st[++etop]=(node){u,w,head[v]},head[v]=etop;}void dfs(int u,int pre,ll d){ dis[u]=d,fa[u]=pre; for(int j=head[u];~j;j=st[j].nxt){ node now=st[j]; if(now.v!=pre)dfs(now.v,u,d+now.w); }}struct cmp{bool operator()(int &a,int &b)const{return dis[a]<dis[b];}};bool check(int u,int pre,bool flag){ if(flag)return 1; bool f=0; for(int j=head[u];~j;j=st[j].nxt){ int v=st[j].v; if(v==pre)continue; f=1; if(!check(v,u,flag|mk[v]))return 0; }return f;}bool check(ll T){ memset(mk,0,sizeof(mk)); memset(rest,-1,sizeof(rest)); priority_queue<int>q1; priority_queue<int,vector<int>,cmp>q2; for(int i=1;i<=m;i++){ int u=army[i]; while(fa[u]&&fa[u]!=1&&dis[army[i]]-dis[fa[u]]<=T)u=fa[u]; if(fa[u]!=1||T<dis[army[i]])mk[u]=1; else{ int v=T-dis[army[i]]; if(rest[u]==-1)rest[u]=v; else{ if(rest[u]>v)swap(rest[u],v); q1.push(v); } } } for(int j=head[1];~j;j=st[j].nxt){ int v=st[j].v; if((~rest[v])&&(check(v,1,mk[v])||rest[v]>=dis[v]))q1.push(rest[v]); else if(~rest[v])mk[v]=1; } for(int j=head[1];~j;j=st[j].nxt){ int v=st[j].v; if(!check(v,1,mk[v]))q2.push(v); } while(!q1.empty()&&!q2.empty()){ int v=q2.top(); if(q1.top()>=dis[v]){ mk[v]=1; q1.pop(); q2.pop(); }else q1.pop(); }return check(1,0,0);}int main(){ Rd(n); int cnt=0; memset(head,-1,sizeof(head)); for(int i=1,u,v,w;i<n;i++){ Rd(u),Rd(v),Rd(w); if(u==1||v==1)cnt++; add_edge(u,v,w); }Rd(m); for(int i=1;i<=m;i++)Rd(army[i]); if(cnt>m){puts("-1");return 0;} dfs(1,0,0); int l=0; ll r=oo; ll ans=-1; while(l<=r){ int md=l+r>>1; if(check(md))ans=md,r=md-1; else l=md+1; }cout<<ans<<endl; return 0;}
虽然能过,但是有点慢,是因为想偷点懒,所以在向上的时候没有“跳”。
【思路】
1、写过了。
2、枚举->二分
3、枚举->贪心->二分答案
总的来说,如果有恶心的数学题,还是乖乖地先去敲出暴力再去想正解吧,虽然说可能性并不大。同时二分答案也是解题的一个思路之一,在想问题的时候一定要往上面去想一想,套一套。还有就是第三题,有了思路并不代表有了一切,最终还是要把它实现出来啊。
- NOIP2012复赛DAY2
- NOIP2012 Day2
- NOIP2012复赛提高组day2(A:同余方程 B:借教室 C:疫情控制)
- NOIP2012复赛DAY1
- NOIP2012提高组Day2
- NOIP2011复赛DAY2
- NOIP2012 day2 T3 疫情控制
- noip2012 day2 T3 疫情控制
- NOIP2012 Day2 T2 借教室
- NOIP2012普及组复赛解题报告
- noip2012提高组复赛 解题报告
- NOIP2012 提高组 复赛 day1 game
- NOIP2012 提高组复赛解题报告
- NOIP2012提高组复赛题4题
- NKOJ-1887 借教室 【NOIP2012 day2】
- 7.12 noip2103提高组复赛day2
- NOIP2012 提高组 复赛 day1 vigenere vigenere密码
- NOIP2012 提高组 复赛 day1 game 国王游戏 再见
- C++学习笔记五——函数重载(多态)、函数模板及函数模板重载和完全匹配与最佳匹配
- 【学习笔记】【Coursera】【MachineLearning】Neural Networks
- [Lintcode]Rotate List旋转链表
- 思维,方法与想法
- Sublime Package Control:There are no packages available for installation
- NOIP2012复赛DAY2
- ASP.NET会话(Session)保存模式
- Redis入门(二)列表List
- 优秀的前端开发工程师简历是怎么样的?
- jQuery中的Ajax
- JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解
- PLSQL Developer 11 破解
- C#中使用抽象类的要求
- JAVA利用SMS发送短信功能模块的开发