Contest_5 0612 By lhq

来源:互联网 发布:东线德军 知乎 编辑:程序博客网 时间:2024/05/22 21:29

题目来源:学军中学NOIP2013提高组原创模拟题day1
https://wenku.baidu.com/view/c766b6b7915f804d2a16c141.html?from=search

Solution

1.装果子 关键词:二分
二分V,然后每次O(n)判断一遍。如果可以装进全部的果子就二分左区间,如果不行就二分右区间。
开long long是必然的。
时间复杂度:O(nlog(2,10^14))

2.零件加工 关键词:贪心
按照t/s升序排序然后计算,比较大小的时候注意交叉相乘。
详细证明见HK’blog:http://blog.csdn.net/yuyaohekai/article/details/73182025
对于最后20%的数据相乘时可以使用二进制乘法以避免高精度
时间复杂度:O(nlog2n)

3.种树 关键词:差分约束系统 or 贪心
解法一:
开一个s数组记录前缀和。
根据题意我们可以得到3个约束条件:
s[r]-s[l-1]≥c,①
s[i]≥s[i-1],②
s[i]-s[i-1]≤k,③
根据①得s[l]-s[r]≤-c,在r和l-1之间连一条权值为-c的边。
根据②得s[i-1]-s[i]≤0,在i和i-1之间连一条权值为0的边。
根据③在i-1和i之间连一条权值为k的边。
50分算法:Bellman-Ford。
时间复杂度:O(nm)
70分算法:SPFA。
时间复杂度:O(km)
100分算法:
观察到最大可能需要连150w条边,因此我们要考虑有些边是否需要连。
我们可以只根据条件①计算,每次更新后O(n)检查是否满足条件②和③,如果不满足就修改,这样只用连50w条边,可以过全部数据。
Tip:事实上SPFA可以过100%

解法二: 贪心
题目中要求要种树种得少,就要使一棵树给多个区间使用,这样,尽量在重叠区间种树即可,而重叠位置一定是区间尾部。处理问题时,先按所有区间的结束位置排序,若结束位置相同,则按开始位置从大到小排序。之后依次处理每个区间,先在第一个区间尾部种满足要求的树,对下一个区间,看差多少棵就在该区间尾部种多少。
【算法步骤】:
1.先快排
2.对每个区间依次处理
a.从前到后扫描这个区间,统计点的个数;
b.若点的个数超过了要求的点数,则continue;
c.从该区间后向前扫描,添加覆盖点。
3.输出ans
Tip:这种方法只适用于小数据,对于大数据我们可以用树状数组加快求和,即过程a,还可以用并查集的方法来加速种树过程c,当有一段区间的树种满时把它与前一个区间合并就行了。

总结:

T1水过,T2没想到贪心,T3排序打错。。
T2的证明中我们有了发现:那就是比较之后的两种选择哪种更优,而不是拿出一种来算,有点差分约束的思想

CODE

T1

#include<bits/stdc++.h>using namespace std;#define ll long longll a[100100],n,m;ll read(){    ll w=0,ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') w=w*10+ch-48,ch=getchar();    return w;   }bool check(ll v){    ll num=1,bag=v;    for (ll i=1;i<=n;i++)        if (bag>=a[i]) bag-=a[i];        else if (num<m) num++,bag=v-a[i];        else return false;    return true;    }ll binary_answer(ll l,ll r){    ll ans;    while (l<=r)    {        ll mid=(l+r)>>1;        if (check(mid)) ans=mid,r=mid-1;        else l=mid+1;           }    return ans; }int main(){    n=read(); m=read();    for (ll i=1;i<=n;i++)        a[i]=read();    ll min_val=0,max_val=0;    for (ll i=1;i<=n;i++)        min_val=max(min_val,a[i]),max_val+=a[i];    ll ans=binary_answer(min_val,max_val);    printf("%lld",ans);    return 0;}

T2

#include<bits/stdc++.h>using namespace std;#define ll long long#define MAXN 100010ll n,m,tot,ans;struct node {    ll t,s;}a[MAXN];bool cmp(node a,node b){    return a.t*b.s<a.s*b.t;}ll read(){    ll w=0,ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') w=w*10+ch-48,ch=getchar();    return w;   }ll mul(ll a,ll b){    ll ans=0;    while (b)    {        if (b&1) ans=(ans+a)%m;        a=(a+a)%m;        b=b>>1;         }    return ans; }int main(){    n=read(); m=read();    for (int i=1;i<=n;i++)        a[i].t=read(),a[i].s=read();    sort(a+1,a+n+1,cmp);    for (int i=1;i<=n;i++)    {        ans=(ans+mul(tot,a[i].s))%m;        tot=(tot+a[i].t)%m;    }    cout<<ans<<endl;    return 0;}

T3 差分约束

#include<bits/stdc++.h>using namespace std;const int MAXN=500010,MAXM=1500010;int Head[MAXN],Next[MAXM],dis[MAXN],n,m,tot;int que[MAXN*2];bool vis[MAXN];struct Edge{    int v,w;    Edge():v(0),w(0){};    Edge(int _v,int _w):v(_v),w(_w){};}E[MAXM];int read(){    int w=0,ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') w=w*10+ch-48,ch=getchar();    return w;   }void AddEdge(int u,int v,int w){    tot++;    Next[tot]=Head[u];    Head[u]=tot;    E[tot]=Edge(v,w);}void spfa(int s){    int l,r;    memset(dis,0x3f,sizeof(dis));    memset(vis,false,sizeof(vis));    dis[s]=0; l=1; r=2; que[l]=s; vis[s]=true;    while (l<r)    {        int u=que[l];        l++; vis[u]=false;        for (int i=Head[u];i;i=Next[i])        {            int v=E[i].v,w=E[i].w;            if (dis[v]>dis[u]+w)            {                dis[v]=dis[u]+w;                if (!vis[v]) que[r++]=v,vis[v]=true;            }        }    }}int main(){    n=read(); m=read();    for (int i=1;i<=n;i++)    {        int k=read();        AddEdge(i,i-1,0),AddEdge(i-1,i,k);    }    for (int i=1;i<=m;i++)    {        int x,y,z;        x=read(); y=read(); z=read();        AddEdge(y,x-1,-z);          }    spfa(n);    cout<<-dis[0]<<endl;    return 0;}

T3 贪心

#include<bits/stdc++.h>using namespace std;#define ll long longconst ll MAXN=5e5+100,MAXM=5e5+100;struct node{    ll l,r,c;}a[MAXM];ll n,m,k[MAXN],tree[MAXN],BIT[MAXN],fa[MAXN];ll read(){    ll w=0,ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') w=w*10+ch-48,ch=getchar();    return w;   }bool cmp(const node &a,const node &b){    if (a.l==b.l && a.r==b.r) return a.c>b.c;    if (a.r==b.r) return a.l>b.l;    return a.r<b.r;}//BIT;void add(ll x,ll val){    for (ll i=x;i<=n;i+=i&-i)        BIT[i]+=val;}ll sum(ll x){    ll ans=0;    for (ll i=x;i>0;i-=i&-i)        ans+=BIT[i];    return ans;}ll sum(ll x,ll y){ return sum(y)-sum(x-1); }//set;void make_set(){    for (ll i=1;i<=n;i++) fa[i]=i;}ll getfa(ll x){    if (fa[x]==x) return x;    fa[x]=getfa(fa[x]);    return fa[x];}void merge(ll x,ll y){    x=getfa(x); y=getfa(y);    if (x!=y)        if (y>x) fa[y]=x;        else fa[x]=y;}//solve;void solve(){    make_set();    for (ll i=1;i<=m;i++)    {        ll num=a[i].c;        num-=sum(a[i].l,a[i].r);        if (num<=0) continue;        for (ll j=a[i].r;j>=a[i].l && num>0;j=getfa(j))        {        if (k[j]>tree[j])            if (num<=k[j]-tree[j]) add(j,num),tree[j]+=num,num=0;            else num-=k[j]-tree[j],add(j,k[j]-tree[j]),tree[j]=k[j];        if (tree[j]==k[j]) merge(j-1,j);        }    }}int main(){    n=read(); m=read();    for (ll i=1;i<=n;i++)        k[i]=read();    for (ll i=1;i<=m;i++)        a[i].l=read(),a[i].r=read(),a[i].c=read();    sort(a+1,a+1+m,cmp);    solve();    ll ans=0;    for (ll i=1;i<=n;i++)        ans+=tree[i];    printf("%lld",ans);     return 0;}
原创粉丝点击