应老李的要求来写一写每周の博客...
真的好麻烦啊
啊
今天考了2011年noip D2的题..
喔好难啊...
第一题只有80分 第二题半暴力只拿了一半的分 第三题直接不会做...
还是做题做少了呀
现在总结一波
第一题
求(ax+by)^k 的x^ny^m项的系数 (m+n=k)
看题目就是一道二项式定理 但是由于我忘记系数是怎么求的了(逃
所以我就想的递推 班上还有小伙伴打了个杨辉三角形板子然后加快速幂
至于80分的原因是没有好好读题 (日常不读题1/1 忽略掉了k=0的情况...好可惜啊
代码 (注释掉的是杨辉三角形的板子
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define mod 10007
using namespace std;
typedef long long ll;
int a,b,n,m,k;
ll s[1001][1001];
int main(){
freopen("factor.in","r",stdin);
freopen("factor.out","w",stdout);
scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
/*if(a==1&&b==1){
s[1][1]=1;
s[1][2]=2;
for(int i=2;i<=k;i++)
s[i][1]=1;
for(int i=2;i<=k;i++)
s[i][i+1]=1;
for(int i=2;i<=k;i++)
for(int j=2;j<=i;j++)
s[i][j]=(s[i-1][j-1]%mod+s[i-1][j]%mod)%mod;
printf("%I64d",s[k][m+1]);
}
else {*/
if(k==0){
printf("1");
return 0;
}
s[1][1]=a%mod;
s[1][2]=b%mod;
for(int i=2;i<=k;i++)
s[i][1]=s[i-1][1]*a%mod;
for(int i=2;i<=k;i++)
s[i][i+1]=s[i-1][i]*b%mod;
for(int i=2;i<=k;i++)
for(int j=2;j<=i;j++)
s[i][j]=(s[i-1][j]*a%mod+s[i-1][j-1]*b%mod)%mod;//递推
printf("%I64d",s[k][m+1]);
//}
return 0;
}
第二题
有n个物品 给一个重量wi 以及价值vi 检验这批物品。
1、给定m 个区间[Li,Ri];
2、选出一个参数W;
3、对于一个区间[Li,Ri],计算检验值
j 是物品编号
这批物品的检验结果Y 为各个区间的检验值之和。即:
给定一个标准值S 通过调整参数W 的值 让检验结果尽可能的靠近标准值S
即 使得S-Y 的绝对值最小 求出这个最小值。
其实就是一道二分W的题
但是我在检验二分值的时候复杂度太高了 当时想了一个伪线段树 后来才知道可以用前缀和
他们真的好聪明啊
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const ll N=200000+5;
ll s,ans;
ll n,m,v[N],w[N],f[N],num[N];
struct section{
ll lf,rg;
}q[N];
ll work(ll x){
memset(num,0,sizeof(num));
memset(f,0,sizeof(f));
for(ll i=1;i<=n;i++){
if(w[i]>=x){
num[i]=1;
f[i]=v[i];
}
f[i]+=f[i-1];
num[i]+=num[i-1];
}
ll ans=0;
for(ll i=1;i<=m;i++){ //前缀和
int ll=q[i].lf;
int rr=q[i].rg;
ans=ans+(num[rr]-num[ll-1])*(f[rr]-f[ll-1]);
}
return ans;
}
int main(){
freopen("qc.in","r",stdin);
freopen("qc.out","w",stdout);
scanf("%I64d%I64d%I64d",&n,&m,&s);
ll minw=1e9;
ll maxw=-minw;
for(ll i=1;i<=n;i++){
scanf("%I64d%I64d",&w[i],&v[i]);
if(w[i]>maxw) maxw=w[i];
if(w[i]<minw) minw=w[i];
}
for(ll i=1;i<=m;i++)
scanf("%I64d%I64d",&q[i].lf,&q[i].rg);
ll l=minw,r=maxw+1;
ll ans=1e18;
while(l<=r){ //二分
ll mid=(l+r)>>1;
ll cmp=work(mid);
ll delta=abs(s-cmp);
if(delta<ans) ans=delta;
if(cmp<s) r=mid-1;
else if(cmp>s) l=mid+1;
else break;
}
printf("%I64d",ans);
return 0;
}
第三题
啊 好难
题目大意:
...
.....
算了不大意了 概括没学好 概括不来这题 直接上题
【问题描述】
风景迷人的小城 Y 市,拥有n 个美丽的景点。由于慕名而来的游客越来越多,Y 市特
意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第0 分钟出现在1
号景点,随后依次前往2、3、4……n 号景点。从第i 号景点开到第i+1 号景点需要Di 分钟。
任意时刻,公交车只能往前开,或在景点处等待。
设共有 m 个游客,每位游客需要乘车1 次从一个景点到达另一个景点,第i 位游客在
Ti 分钟来到景点Ai,希望乘车前往景点Bi(Ai<Bi)。为了使所有乘客都能顺利到达目的地,
公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。
假设乘客上下车不需要时间。
一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一
辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司
机ZZ 给公交车安装了k 个氮气加速器,每使用一个加速器,可以使其中一个Di 减1。对于
同一个Di 可以重复使用加速器,但是必须保证使用后Di 大于等于0。
那么 ZZ 该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?
输入
第 1 行是3 个整数n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。
第 2 行是n-1 个整数,每两个整数之间用一个空格隔开,第i 个数表示从第i 个景点开
往第i+1 个景点所需要的时间,即Di。
第 3 行至m+2 行每行3 个整数Ti, Ai, Bi,每两个整数之间用一个空格隔开。第i+2 行表
示第i 位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。
输出最小的旅行时间
这道题 我开始想的贪心 乱贪一气还觉得自己贪的天衣无缝...
后来才发现自己还是太年轻了 (永远不要相信小样例..
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxint=1000000000;
int n,m,k;d[10001],t[10001],a[10001],b[10001],latest[10001],
int arrive[10001],sum[10001],next[10001],ans=0,qqq,dd,maxl;
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int main(){
freopen("bus.in","r",stdin);
freopen("bus.out","w",stdout);
memset(latest,0,sizeof(latest));
memset(sum,0,sizeof(sum));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n-1;i++)
scanf("%d",&d[i]);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&t[i],&a[i],&b[i]);
if(t[i]>latest[a[i]])
latest[a[i]]=t[i];
sum[b[i]]++;
}
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1];
while(1){
maxl=1;
//计算arrive[i] 表示bus到达第i个景点的时间。
arrive[1]=0;
for(int i=2;i<=n;i++)
arrive[i]=max(arrive[i-1],latest[i-1])+d[i-1];
//计算next[i]表示在第i个景点后离第i个景点最近的满足latest[i]>=arrive[i](即bus到的时间比最后到的乘客时间早)的景点。
//即第i个景点到next[i]-1个景点均是bus到的时间比最后到的乘客时间晚
next[n]=n;
for(int i=n-1;i;i--){
next[i]=next[i+1];
if(arrive[i+1]<=latest[i+1])
next[i]=i+1;
}
//贪心选择最优的一条边操作,一次操作可以直接使d[i]变为0
while(!d[maxl]&&maxl<=n-1)
maxl++;
if(maxl==n||k==0)
break;
for(int i=maxl+1;i<=n-1;i++)
if(d[i]&&sum[next[maxl]]-sum[maxl]<sum[next[i]]-sum[i])//选择加速要让最多的人受益,只有到达了目的地的乘客才是真正受益。
maxl=i; //经过的乘客不一定受益 因为虽然现在加速了 但后面可能因为等晚到的乘客而没有真正受益
if(sum[next[maxl]]-sum[maxl]==0)
break;
dd=maxint;
for(int i=maxl+1;i<=next[maxl]-1;i++)
dd=min(dd,arrive[i]-latest[i]);
dd=min(dd,k);
dd=min(dd,d[maxl]);
k-=dd;
d[maxl]-=dd;
}
for(int i=1;i<=m;i++)
ans+=arrive[b[i]]-t[i];
printf("%d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
终于写完了..
下周可能还要被老李喊来写这个吧...