第一题杨辉三角形结合推论应该是非常简单的,但是在递推的时候忽略了数据范围(准确地说应该是算错了...),没有mod也没有开long long就直接wa掉7个点...//惨痛教训...
第二题一道十分显然的二分,前缀和思想非常重要!! 类似树状数组的前缀和可以有效地将累加变为o(1)查询;当然还有一个值得注意的地方,整数的二分要考虑正确答案左右的大小,即需要将最终mid左右两边的值算出的答案进行比较。 正确性十分显然就不再赘述。。
第三题是一道贪心。贪心法则十分具有迷惑性,并不是经过的越多的边就要用加速器,而是下车时才能获得实际收益。教程如下:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,k;
int d[10001];
int t[10001],a[10001],b[10001];
int latest[10001];
int arrive[10001];
int sum[10001];
int next[10001];
int ans=0;
int qqq;
int dd;
int maxl;
int maxint=1000000000;
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;
}