NOIP2011复赛提高组day2(A:计算系数 B:聪明的质监员 C:观光公交)
2016-10-30 19:12
387 查看
A题:
联赛第一题,就是送分的,
这次是用组合数学送,
只要你学过二项式定理(有点水平的教练应该都会讲),
基本上是秒杀,
不过要注意的是mod
这题按理来说是不需要long long的,但是保险起见,还是加一个吧,又不会狗带
蒟蒻的lowest代码上线:
B题:
话说11年两天的第二题似乎都很水
基本上快和第一题一个水平了
这题显然满足二分的性质
于是就二分吧
二分之后就更水了
前缀和维护一下区间基本就结束了
(前两题我只敲了30+就好了)
然而考完试听到xiaoC说有人敲出了主席数、线段树、数状数组等等的时候
你们无法想象我当时的表情
简直惊为天人,(蒟蒻现在连主席数模板都不会敲0.0)
他们的脑洞实在有点大。。。
一个离线的区间维护问题,最简单的不就是前缀和么~~~
代码get:
C题:
这题简直了!!
敲了150+只有30分,欲哭无泪
虽说博主当时本来就是奔着水分去的
(考试的时候想到了贪心,但是一时证明不了正确性、也没有想到什么好办法去模拟)
于是敲暴力。。
xiaoC大人告诉我们要学会切分,
于是我首先花了40+的时间敲了20%的数据:
也不知道我当时是怎么想的。
跟day1的情况几乎一模一样
那个Mayan 游戏我费了60+的时间敲30%数据(只有一行)
(调试了半天)
然而敲完了发现,那完全可以直接枚举。。
瞬间KO的
于是回归主题,
这题只要再深入思考一下,
就可以明确这是贪心
我们只要找到使用加速器后对结果影响最大的那条边就可以了
这个贪心这么证明其正确性呢
显然的是
在某条边使用了加速器之后
如果到达了之后的某个点时需要等人
加速器就对在之后的点下车的乘客不起丝毫效果
也就是说我们在使用了加速器改变了这条边的权值之后
对其他区域是不会有影响的
这些区域完全独立
于是我们可以直接枚举每一个加速器使用在那条边上
但是枚举这条边时显然是不能傻傻的一遍枚举过来的、
那样O(k*n^2)会T的
于是这个时候我们再仔细想想就会发现
对于某一个满足条件的区间来说
在它的左端点使用加速器显然要优于其他端点
于是这满足尺取法的性质
每次选完一个最大区间
就从区间的右端点开始重新贪心就行了
复杂度为O(n*k)
最后计算所需时间时
只要将下车总时间减去上车总时间就可以得出答案了
其实这一题在加上一个优先队列可以将复杂度进一步优化到O(n*logn)
但由于博主是蒟蒻,就不说明了
代码来袭:
于是两天相加450瞬间爆炸
联赛第一题,就是送分的,
这次是用组合数学送,
只要你学过二项式定理(有点水平的教练应该都会讲),
基本上是秒杀,
不过要注意的是mod
这题按理来说是不需要long long的,但是保险起见,还是加一个吧,又不会狗带
蒟蒻的lowest代码上线:
#include<bits/stdc++.h> using namespace std; #define M 1005 const int P=10007; int Com[M][M]; int getCom(int n,int m){ if(Com [m])return Com [m]; return Com [m]=(getCom(n-1,m)+getCom(n-1,m-1))%P; } int main(){ int a,b,k,n,m,ans=1; scanf("%d%d%d%d%d",&a,&b,&k,&n,&m); if(n+m!=k){ puts("0"); return 0; }for(int i=1;i<=n;i++)ans=1ll*ans*a%P; for(int i=1;i<=m;i++)ans=1ll*ans*b%P; for(int i=0;i<=k;i++){Com[i][0]=1;Com[i][i]=1;} ans=1ll*ans*getCom(k,n)%P; printf("%d\n",ans); return 0; }
B题:
话说11年两天的第二题似乎都很水
基本上快和第一题一个水平了
这题显然满足二分的性质
于是就二分吧
二分之后就更水了
前缀和维护一下区间基本就结束了
(前两题我只敲了30+就好了)
然而考完试听到xiaoC说有人敲出了主席数、线段树、数状数组等等的时候
你们无法想象我当时的表情
简直惊为天人,(蒟蒻现在连主席数模板都不会敲0.0)
他们的脑洞实在有点大。。。
一个离线的区间维护问题,最简单的不就是前缀和么~~~
代码get:
#include<bits/stdc++.h> using namespace std; #define M 200005 #define LL long long 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)); } int n,m; int wei[M],val[M],lef[M],rig[M],num[M]; LL sum[M]; LL check(int W){ LL res=0; for(int i=1;i<=n;i++){ sum[i]=sum[i-1];//前缀和分别维护重量和个数 num[i]=num[i-1]; if(wei[i]>=W){ sum[i]+=val[i]; num[i]++; } }for(int i=1;i<=m;i++)res+=(sum[rig[i]]-sum[lef[i]-1])*(num[rig[i]]-num[lef[i]-1]); return res; } int main(){ LL S; cin>>n>>m>>S; for(int i=1;i<=n;i++){Rd(wei[i]);Rd(val[i]);} for(int i=1;i<=m;i++){Rd(lef[i]);Rd(rig[i]);} int l=1,r=1e6;LL ans=2e15; while(l<=r){ int mid=l+r>>1;LL res=check(mid); if(abs(res-S)<ans)ans=abs(res-S); if(res<S)r=mid-1; else if(res>S)l=mid+1; else break; }cout<<ans<<endl; return 0; }
C题:
这题简直了!!
敲了150+只有30分,欲哭无泪
虽说博主当时本来就是奔着水分去的
(考试的时候想到了贪心,但是一时证明不了正确性、也没有想到什么好办法去模拟)
于是敲暴力。。
xiaoC大人告诉我们要学会切分,
于是我首先花了40+的时间敲了20%的数据:
对于10% 的数据,k=0 ;
对于20% 的数据,k=1 ;
。。。。。。。也不知道我当时是怎么想的。
跟day1的情况几乎一模一样
那个Mayan 游戏我费了60+的时间敲30%数据(只有一行)
(调试了半天)
然而敲完了发现,那完全可以直接枚举。。
瞬间KO的
于是回归主题,
这题只要再深入思考一下,
就可以明确这是贪心
我们只要找到使用加速器后对结果影响最大的那条边就可以了
这个贪心这么证明其正确性呢
显然的是
在某条边使用了加速器之后
如果到达了之后的某个点时需要等人
加速器就对在之后的点下车的乘客不起丝毫效果
也就是说我们在使用了加速器改变了这条边的权值之后
对其他区域是不会有影响的
这些区域完全独立
于是我们可以直接枚举每一个加速器使用在那条边上
但是枚举这条边时显然是不能傻傻的一遍枚举过来的、
那样O(k*n^2)会T的
于是这个时候我们再仔细想想就会发现
对于某一个满足条件的区间来说
在它的左端点使用加速器显然要优于其他端点
于是这满足尺取法的性质
每次选完一个最大区间
就从区间的右端点开始重新贪心就行了
复杂度为O(n*k)
最后计算所需时间时
只要将下车总时间减去上车总时间就可以得出答案了
其实这一题在加上一个优先队列可以将复杂度进一步优化到O(n*logn)
但由于博主是蒟蒻,就不说明了
代码来袭:
#include<bits/stdc++.h> using namespace std; #define N 1010 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)); } int d ,ti ,cost ,Add ; //d[x]代表x到x+1的距离 //ti[x]代表最后一个在点x上车的乘客的上车时间 //cost[x]代表在当前状态下,到达点x的时间 //Add[x]代表在点x下车的人数 int n,m,k; void solve(){ while(k--){ int l=1,r=2,add,T=0,mx=0,id=-1; for(int i=1;i<=n;i++){//在使用加速期之后cost的值将会改变 cost[i]=T+d[i-1]; T=max(cost[i],ti[i]); }while(r<=n){ while(d[l]==0&&r<=n)l++,r++;//d不能小于0 if(r>n)break; add=Add[r]; while(r<=n){ if(cost[r]<=ti[r])break; //当汽车到达点i的时间小于等于最后一个乘客上车时间时,加速器对之后的点无影响 add+=Add[++r]; }if(add>mx){ mx=add; id=l; }l=r;r++; }if(id!=-1)d[id]--; else break;//无法再使用加速器了了 } } int main(){ int sum=0; scanf("%d %d %d",&n,&m,&k); if(n==1){puts("0");return 0;} for(int i=1;i<n;i++)Rd(d[i]); for(int i=1;i<=m;i++){ int t,a,b; Rd(t);Rd(a);Rd(b); sum+=t; if(t>ti[a])ti[a]=t; Add[b]++; }solve(); int T=0; for(int i=1;i<=n;i++){//重新计算到某一点的距离 cost[i]=T+d[i-1]; T=max(cost[i],ti[i]); }int ans=0; for(int i=1;i<=n;i++)ans+=Add[i]*cost[i]; cout<<ans-sum<<endl; return 0; }
于是两天相加450瞬间爆炸
相关文章推荐
- 全国信息学奥林匹克联赛(NOIP2011)复赛 提高组 day2 T2 聪明的质监员
- NOIP 2011 提高组 复赛 day2 qc 聪明的质监员
- NOIP 2011 提高组 复赛 day2 bus 观光公交
- NOIP 2011 提高组 复赛 day2 factor 计算系数
- [NOIP2011提高组day2]-1-计算系数
- [NOIP2011提高组day2]-2-聪明的质监员
- [NOIP2011提高组day2]-3-观光公交
- Noip2011 提高组 Day1 T1 铺地毯 + Day2 T1 计算系数
- 【NOIP2011 day2】观光公交
- NOIP2011 day2 第一题 计算系数
- [luogu-1314]noip2011 day2-T2聪明的质监员 题解
- noip2011 day2-2 聪明的质监员
- NOIP2011提高组 聪明的质监员 -SilverN
- NOIP2011 Day2 T2 聪明的质监员
- 计算系数(NOIP2011提高组Day2T1)
- NOIP2011 day2 第一题 计算系数
- [NOIP2011提高组]聪明的质监员
- 【NOIP2011提高组T5】聪明的质监员-二分答案+前缀和
- NOIP提高组2011 观光公交
- 洛谷P1313 [NOIP2011提高组Day2T1]计算系数