1.27 动归赛II总结
Posted sjsjsj-minus-si
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1.27 动归赛II总结相关的知识,希望对你有一定的参考价值。
t1mzoj 1354: 最大子序列的和
得分:10pts,本题我打了一个半小时,1.单调队列不熟悉,2.数据范围看错了,空间爆掉,死死翘翘!
思路:
看到区间的问题首先肯定是想到求前缀和,
我们把[1,k]的和记为sum[k],可以得到sum[i] = sum[i - 1] + a[i],[l,r]的和即为sum[r] - sum[l - 1](这里视sum[0] = 0)。(减法原理)
我们假设选择的区间为[l,r]且r固定,可知r?B+1≤l≤r?A+1若要使[l,r]区间的值最大,则sum[l - 1]需最小,才可使得sum[r] - sum[l - 1]最小。当i右移一位到i+1,因为p,q为给定不变的值,对应寻找最小sum[l-1]的区间也右移一位。
#include<bits/stdc++.h>
#define ll long long
#define N 1000010
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int read()
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9')if(c=='-')f=-1;c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0';c=getchar();
return x*f;
ll sum[N],q[N];
ll n,ans=-2147483647,A,B;
int main()
//freopen("input.txt","r",stdin);
n=read(),A=read(),B=read();
rep(i,1,n)
sum[i]=sum[i-1]+read();
int head=0,tail=1;
rep(i,A,n)
while(head<=tail && q[head]<i-B)//不处于维护范围内的,出队
head++;
while(head<=tail && sum[i-A]<=sum[q[tail]])//更优的sum[l - 1]予以插队
tail--;
q[++tail]=i-A;
ans=max(ans,sum[i]-sum[q[head]]);//更新答案
printf("%lld\n",ans);
return 0;
插播一条线段树做法
#include<bits/stdc++.h>
using namespace std;
const int maxn=500000+5;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
ll s[maxn];
int n,a,b;
ll mi[maxn<<2];
void pushup(int rt)
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
void buildtree(int l,int r,int rt)
if(l==r)
mi[rt]=s[l];
return;
int m=(l+r)>>1;
buildtree(lson);
buildtree(rson);
pushup(rt);
ll query(int L,int R,int l,int r,int rt)
//printf("%d %d,%d %d %d\n",L,R,l,r,rt);
if(R<=0)return 0;
if(R<l||L>r) return 1e15;
if (L<=l&& R>=r)
return mi[rt];
int m=(l+r)>>1;
ll ans=1e15;
if(L<=m)ans=min(ans,query(L,R,lson));
if(R>m)ans=min(ans,query(L,R,rson));
return ans;
ll read()
ll x=0,f=1;char s=getchar();
while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
while(s>='0'&&s<='9')x=x*10+s-'0';s=getchar();
return x*f;
void init()
freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
void readdata()
n=read();a=read();b=read();
s[0]=0;
for(int i=1;i<=n;i++)
s[i]=read()+s[i-1];
buildtree(0,n,1);
void work()
ll ans=-1e15;
for (int i=a;i<=n;i++)
ans=max(ans,s[i]-query(max(0,i-b),max(0,i-a),0,n,1));
printf("%lld",ans);
int main()
//init();
readdata();
work();
return 0;
t3 数的划分加强版
得分:10pts 1.因为第一题想写正解,调了太久,没时间啦,想了个玄学暴力只得了10pts………2.前几天才做了一道数的划分,以为是原题,结果!并不是……ouyang skr(是个) 狠人!
/*
1.random_shuffle 随机大法好!
2.状压基本都可以靠随机和模拟退火水过去……还是100分的那种……
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,m,ans,cnt,sum;
int w[20];
int read()
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9')if(c=='-')f=-1;c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0';c=getchar();
return x*f;
int main()
n=read(),m=read();
ans=n;//最坏情况
rep(i,1,n)
w[i]=read();
rep(times,1,1000000)
random_shuffle(w+1,w+n+1);
sum=0,cnt=0;
rep(i,1,n)
sum+=w[i];
if(sum>m)
++cnt;
sum=w[i];
if(sum)++cnt;
ans=min(ans,cnt);
printf("%d",ans);
return 0;
还有一种贪心思想:即小的数字更加灵活,先从大的数字枚举
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dwn(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n,m,ans;
long long w[20],sum[20];
bool vis[20];
int read()
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9')if(c=='-')f=-1;c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0';c=getchar();
return x*f;
int main()
//freopen("input.txt","r",stdin);
n=read(),m=read();
rep(i,1,n)
w[i]=read();
sort(w+1,w+n+1);
dwn(i,n,1)//精髓
if(!vis[i])
sum[i]=w[i];
dwn(j,i-1,1)//精髓
if(!vis[j]&&sum[i]+w[j]<=m)
vis[j]=1;
sum[i]+=w[j];
rep(i,1,n)
if(sum[i])
ans++;
printf("%d",ans);
return 0;
以上是关于1.27 动归赛II总结的主要内容,如果未能解决你的问题,请参考以下文章