NOIP 模拟题 奶牛抗议

在这里插入图片描述
题解:
这道题一看就不难得出这是一道dp题,设sum[i]是a[1]-a[i]的和,那么显然可得当sum[i]-sum[j]>=0时dp[i]可以从dp[j]处转移,那么就把所有满足条件的dp[j]加起来。于是乎可得方程dp[i]=∑dp[j] (sum[i]>=sum[j])

给出一份可在某谷上过的代码:

#include<bits/stdc++.h>
#define M 1000000009
using namespace std;
long long A[100005];
int n;
long long dp[100005];
int read(){
	int num=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		num=(num<<1)+(num<<3)+ch-'0';
		ch=getchar();
	}
	return num*f;
}
int main(){
	n=read();
	int x=0;
	for(int i=1;i<=n;i++){
		A[i]=read();
		A[i]+=A[i-1];
		if(!x){
			if(A[i]>0){
				x=i;
				dp[x]=1;
			}
			continue;
		}
	}
	if(!x||A[n]<0){
		puts("0");
		return 0;
	}
	for(int i=x+1;i<=n;i++){
		if(A[i]>=0){
			dp[i]=1;
			for(int j=x;j<i;j++){
				if(dp[j]&&(A[i]-A[j]>=0)){
					dp[i]+=dp[j];
					dp[i]%=M;
				}
			} 
		}
	}
	cout<<dp[n]%M;
} 

然而众所周知某谷上的数据实在太水了,只要复杂一点的数据这个代码就只有90了
所以要用树状数组或线段树维护;

#include<bits/stdc++.h>
#define mod 1000000009
#define ll long long
using namespace std;
int n,size;
int a[1001000];
int sum[1001000];
int c[1001000];
struct node {
	int bh,v,lsh;
} Tree[1001000];
int read() {
	int num=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0') {
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		num=(num<<1)+(num<<3)+ch-'0';
		ch=getchar();
	}
	return num*f;
}
int lowbit(int x) {
	return x&(-x);
}
void add(int x,int v) {
	while(x<=size) {
		c[x]=(c[x]+v)%mod;
		x+=lowbit(x);
	}
}
int ask(int x) {
	int ans=0;
	while(x>0) {
		ans=(ans+c[x])%mod;
		x-=lowbit(x);
	}
	return ans;
}
bool com1(node x,node y) {
	return x.v<y.v;
}
bool com2(node x,node y) {
	return x.bh<y.bh;
}
int main() {
	n=read();
	for(int i=1; i<=n; i++) {
		Tree[i].v=read()+Tree[i-1].v;
		Tree[i].bh=i;
	}
	sort(Tree,Tree+n+1,com1);
	int cnt=1;
	Tree[0].lsh=1;
	for(int i=1; i<=n; i++) {
		if(Tree[i].v==Tree[i-1].v)
			Tree[i].lsh=cnt;
		else Tree[i].lsh=++cnt;
	}
	size=cnt;
	sort(Tree,Tree+n+1,com2);
	add(Tree[0].lsh,1);
	int ans;
	for(int i=1; i<=n; i++) {
		ans=ask(Tree[i].lsh);
		add(Tree[i].lsh,ans);
	}
	printf("%d",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值