题目来源:学军中学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.youkuaiyun.com/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 long
ll 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 100010
ll 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 long
const 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;
}