Noip2011提高组总结
这套题思考的难度比较大,应该说是有四题基础题,一题比较复杂的搜索加模拟,还有一题需要深度思考一下。自己的代码漏洞还是很大,而且思考的时候会遗漏一些情况,这些错误都是致命的,去年Noip的惨败也证实了这一点,许多时候,我并没有败在算法上,而是细节与心态上。记住犯过的错误,尽力不在同一个地方摔倒,那么才可能不断进步,否则一直都在原地踏步。
DAY1 》
T1:铺地毯
枚举然后判断,就是考验基础的代码能力
#include <cstdio>
int x,y,ans,n,h[10005],t[10005],l[10005],r[10005];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d%d%d",&h[i],&l[i],&t[i],&r[i]);
ans=-1; scanf("%d%d",&x,&y);
for(int i=1;i<=n;i++)if(h[i]<=x&&(x<=h[i]+t[i])&&l[i]<=y&&(y<=r[i]+l[i]))ans=i;
printf("%d\n",ans);
return 0;
}
T2:选择客栈
首先这还是一道枚举题,边读入边处理出每种颜色的前缀和,同时记录上一个满足最低消费要求的咖啡馆的位置,每次加上这个位置的同颜色前缀和即可,复杂度O(kn)。需要注意的是答案超过了int的范围,需要开long long,而且一开始做这道题是忽略了可以在自己的旅馆喝咖啡的情况,这是不应该的。
#include <cstdio>
#include <iostream>
using namespace std;
const int N=200005;
long long sum;
int pr,n,k,pm,pn,co,s[N][55];
int main(){
scanf("%d%d%d",&n,&k,&pm);
for(int i=1;i<=n;i++){
scanf("%d%d",&co,&pn);
for(int j=0;j<k;j++)s[i][j]=s[i-1][j];
s[i][co]++; if(pn<=pm)pr=i;
if(pr!=i)sum+=(long long)s[pr][co];
else sum+=(long long)s[pr-1][co];
}
cout<<sum<<endl;
return 0;
}
T3:Mayan游戏
直接模拟题目中的坠落,清除和操作的过程,直接按操作的字典序搜索,特别注意相同的两个块不要移动,不同的块不要反复交换,此外要有一个判断,当剩余的彩块有一种没到3个时直接剪枝,因为这种情况一定是无法完成的,然后就是一些自己程序的细节问题要多注意。
#include <cstdio>
#include <cstring>
#include <algotithm>
using namespace std;
const int maxx=10,maxy=12,maxc=15;
int n,c,a[maxx][maxy],cnt[maxc],ans[maxx][3];
bool f[maxx][maxy];
void fall(int x){
for(int i=0;i<7;i++){
if(a[x][i]==0){
int j=i+1;
while(j<7&&a[x][j]==0)j++;
if(j==7)return;
else swap(a[x][i],a[x][j]);
}
}
}
bool clear(){
bool flag=false;
for(int i=0;i<5;i++)
for(int j=0;j<7;j++){
if(!a[i][j]) continue;
if(i<3&&a[i][j]==a[i+1][j]&&a[i][j]==a[i+2][j])
{f[i][j]=1;f[i+1][j]=1;f[i+2][j]=1;}
if(j<5&&a[i][j]==a[i][j+1]&&a[i][j]==a[i][j+2])
{f[i][j]=1;f[i][j+1]=1;f[i][j+2]=1;}
}
for(int i=0;i<5;i++)
for(int j=0;a[i][j]&&j<7;j++)if(f[i][j]){
flag=1;
cnt[a[i][j]]--;
a[i][j]=f[i][j]=0;
}
for(int i=0;i<5;i++)fall(i);
return flag;
}
int check(){
int minc=0;
for(int i=1;i<=c;i++)if(cnt[i])
if(!minc||minc>cnt[i])minc=cnt[i];
return minc;
}
void print(){
for (int i=1;i<=n;i++)
printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
exit(0);
}
void dfs(int move){
int tmpd[maxx][maxy],tmpdc[maxc];
for(int i=0;i<5;i++)for(int j=0;j<7;j++)tmpd[i][j]=a[i][j];
for(int i=1;i<=c;i++)tmpdc[i]=cnt[i];
for (int i=0;i<5;i++)
for(int j=0;a[i][j]&&j<7;j++)
for(int k=1;k>=-1;k-=2)
if(i+k>=0&&i+k<5){
if((k==-1&&a[i-1][j])||a[i][j]==a[i+k][j])continue;
ans[move][0]=i; ans[move][1]=j; ans[move][2]=k;
swap(a[i][j],a[i+k][j]);
fall(i); fall(i+k);
while(clear());
int tmp=check();
if(move==n){if(tmp==0)print();}
else if(tmp>2)dfs(move+1);
for(int i=0;i<5;i++)
for(int j=0;j<7;j++)a[i][j]=tmpd[i][j];
for(int i=1;i<=c;i++)cnt[i]=tmpdc[i];
} }
int main(){
scanf("%d",&n);
int tmp; c=0;
for(int i=0;i<5;i++)
for(int j=0;j<=7;j++){
scanf("%d",&tmp);
if(tmp==0)break;
a[i][j]=tmp;
c=max(c,tmp);
cnt[tmp]++;
}dfs(1);
printf("-1\n");
return 0;
}
DAY2 》
T1:计算系数
基础的二项式展开,先计算出组合数,然后乘上两个数幂即可。
#include <iostream>
typedef long long LL;
const int mod=10007;
using namespace std;
LL ans,a,b,l,k,m,n,c[1500][1500];
LL power(LL a,LL b,LL m){
LL t,y;
t=1; y=a;
while(b){
if(b&1)t=t*y%m;
y=y*y%m; b>>=1;
}return t;
}
int main(){
cin>>a>>b>>k>>n>>m;
ans=1; c[1][1]=1;
for(int i=2;i<=k+1;i++)
for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
ans=c[k+1][m+1];
ans=ans*power(a,n,mod)%mod;
ans=ans*power(b,m,mod)%mod;
cout<<ans<<endl;
return 0;
}
T2:聪明的质检员
由题目可得,根据 w 取值的变化,检验结果具有单调性,所以我们二分答案 w,然后对于 check 的书写,可采用前缀和,记录i 位之前有几个大于 w,即用来计算 l,同时,记录下大于 w 的 v 前缀和,之后用 check 与 s 取差,不断更新最小值。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=200005;
char c;
LL wmax,wmin,ans,tmp,s1,w[N],v[N],h[N],s[N];
int i,j,k,l,m,n,r,mid,r1[N],l1[N];
LL check(LL x){
int i,j;
LL tmp;
memset(h,sizeof(h),0);
memset(s,sizeof(s),0);
h[0]=s[0]=tmp=0;
for(int i=1;i<=n;i++)if(w[i]>=x)
{s[i]=s[i-1]+v[i];h[i]=h[i-1]+1;}
else{s[i]=s[i-1];h[i]=h[i-1];}
for(int i=1;i<=m;i++)
tmp=tmp+(LL)((s[r1[i]]-s[l1[i]-1])*(h[r1[i]]-h[l1[i]-1]));
return tmp;
}
int scan(LL &x){
while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
}
int main(){
cin>>n>>m>>s1;
wmax=0;
wmin=~0U>>1;
for(int i=1;i<=n;i++){
scan(w[i]);scan(v[i]);
if(w[i]>wmax)wmax=w[i];
if(w[i]<wmin)wmin=w[i];
}
for(int i=1;i<=m;i++)scanf("%d%d",&l1[i],&r1[i]);
l=wmin;r=wmax+1;
ans=abs(check(l)-s1);
do{
mid=(l+r)>>1;
tmp=check(mid);
if(tmp==s1){ans=0;break;}
if(tmp<s1){ans=min(ans,abs(tmp-s1));r=mid-1;}
if(tmp>s1){ans=min(ans,abs(tmp-s1));l=mid+1;}
}while(l<=r);
cout<<ans<<endl;
return 0;
}
T3:观光公交
这道题需要先求出不用加速器到达某站需要的总时间,这个很好求,就是每次到达前一站最后一个乘客的时间与到前一站的实际时间的最大值加上中间路程所需要的时间,最终时间记为ans.
然后考虑加速器对时间的影响,采用贪心策略,每个加速器都要用在能使最多人减少时间的地方,需要注意的是,并不是当前在车上的所有人都可以减少时间,因为在如果使用加速器加速后提前到了某站,车上的乘客还是需要在此地等待,时间不变。所以如果在i+1站有会产生等待时间的话,我们在i到i + 1间使用加速器,到i + 1站的乘客的旅行时间都会减一,别的不变,如果没有等待时间,所有人的时间都会减一,所以分情况讨论,计算出每一站公交不在等待上浪费时间最远可以到达的站点,每次求出最大值,在ans中减去,同时维护时间和最远可达站,最后就是答案。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node{int st,ar,ta;}a[20000];
int n,m,K,ans,f[20000],at[20000],next[20000],t[20000],sum[20000];
int main(){
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<n;i++)scanf("%d",&t[i]);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a[i].ar,&a[i].st,&a[i].ta);
f[a[i].st]=max(f[a[i].st],a[i].ar);
sum[a[i].ta]++;
}at[1]=0;
for(int i=2;i<=n;i++)sum[i]+=sum[i-1];
for(int i=2;i<=n;i++)at[i]=max(at[i-1],f[i-1])+t[i-1];
for(int i=1;i<=m;i++)ans+=at[a[i].ta]-a[i].ar;
while(K){
next[n]=next[n-1]=n;
for(int i=n-2;i;i--){
if(at[i+1]<=f[i+1])next[i]=i+1;
else next[i]=next[i+1];
}
int maxn=0,j;
for(int i=1;i<=n;i++)
if(sum[next[i]]-sum[i]>maxn&&t[i]>0)maxn=sum[next[i]]-sum[i],j=i;
if(!maxn)break;
ans-=maxn,t[j]--,K--;
at[1]=0;
for(int i=2;i<=n;i++)at[i]=max(at[i-1],f[i-1])+t[i-1];
}
printf("%d\n",ans);
return 0;
}
注意点:
1.注意数据范围是否超过int,若是需要开long long;
2.注意C++过程中数组不能开过大,大数组要声明在主程序中,在过程中注意要初始化一下;
3.读入优化很重要,如果时间允许最好都做一个读入优化;
4.读题仔细,注意多种情况和一些细枝末节的条件,分类讨论要思考清楚。
Noip2011提高组总结的更多相关文章
- luogu1003铺地毯[noip2011 提高组 Day1 T1]
题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...
- [NOIP2011] 提高组 洛谷P1312 Mayan游戏
题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他方块之上.游戏通关是指在规定 ...
- [NOIP2011] 提高组 洛谷P1315 观光公交
题目描述 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第 0 分钟出现在 1号景点,随后依次前往 2 ...
- [NOIP2011] 提高组 洛谷P1003 铺地毯
题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...
- NOIP2011(提高组)DAY2---观光公交(vijosP1741)
描述 风景迷人的小城Y市,拥有n个美丽的景点.由于慕名而来的游客越来越多,Y市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0分钟出现在1号景点,随后依次前往2.3.4……n号景 ...
- 洛谷-铺地毯-NOIP2011提高组复赛
题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...
- 刷题总结——mayan游戏(NOIP2011提高组day2T3)
题目: 题目背景 NOIP2011提高组 DAY1 试题. 题目描述 Mayan puzzle 是最近流行起来的一个游戏.游戏界面是一个 7 行 5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即 ...
- 洛谷P1003 铺地毯 noip2011提高组day1T1
洛谷P1003 铺地毯 noip2011提高组day1T1 洛谷原题 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n ...
- [Luogu1313][NOIP2011提高组]计算系数
题目描述 给定一个多项式 (by+ax)k(by+ax)^k(by+ax)k ,请求出多项式展开后 xn×ymx^n \times y^mxn×ym 项的系数. 输入输出格式 输入格式: 共一行,包含 ...
- Noip2011 提高组 Day1 T1 铺地毯 + Day2 T1 计算系数
Day1 T1 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小 ...
随机推荐
- English - when用法
一.作为副词,它有以下的用法: 1. 作为疑问副词,引导特殊疑问句,意为“什么时候:何时”.如: ( 1 ) When will they come back?( 2 ) What time wil ...
- Hibernate的使用梳理
Hibernate创建步骤 (五大核心接口:Configuration/SessionFactory/Session/Transaction/Query) 1.新建java工程,导入需要的jar包. ...
- Jquery中的delegate()使用方法介绍
delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数 delegate定义和用法 delegate() 方法为指定的元素(属于被选 ...
- BZOJ 2301: [HAOI2011]Problem b( 数论 )
和POI某道题是一样的... http://www.cnblogs.com/JSZX11556/p/4686674.html 只需要二维差分一下就行了. 时间复杂度O(MAXN + N^1.5) - ...
- struts1标签(html:text)
这个标签可能是出现频率最高的标签了. 功能: <html:text/>产生HTML语句: <input type=”text”…> 也就是在页面上产生input类型的显示标签. ...
- SQL1-(增删改查、常用函数)
USE flowershopdb --全球唯一标识符(GUID UUID) SELECT NEWID() --增删改查 --INSERT [INTO] <表名> [列名] VALUES & ...
- ADODB 数据库Access连接
<?php $filepath=__FILE__;//echo __FILE__;$newarray=explode("\\",$filepath);$num=count($ ...
- PHP合并数组+与array_merge的区别分析
主要区别是两个或者多个数组中如果出现相同键名,键名分为字符串或者数字,需要注意 1)键名为数字时,array_merge()不会覆盖掉原来的值,但+合并数组则会把最先出现的值作为最终结果返回,而把后面 ...
- php框架
使用composer构建的php框架 github: https://github.com/Ev2le0/LeoFramework 实现功能: 1)路由 2)ORM 3)视图
- iPhone 5s网络钓鱼邮件,和苹果发布会同步亮相
正如预期的一样,网络犯罪分子会利用Apple最新发表的iPhone 5s消息,几乎在苹果的新产品发表会同时,这个网络钓鱼(Phishing)信件开始流传.此次,趋势科技病毒防治中心 Trend Lab ...