[JSOI2008]最大数 洛谷p1198

题目描述

现在请求你维护一个数列,要求提供以下两种操作:

1、 查询操作。

语法:Q L

功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值。

限制:L不超过当前数列的长度。

2、 插入操作。

语法:A n

功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列的末尾。

限制:n是整数(可能为负数)并且在长整范围内。

注意:初始时数列是空的,没有一个数。

输入输出格式

输入格式:

第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足(0<D<2,000,000,000)

接下来的M行,每行一个字符串,描述一个具体的操作。语法如上文所述。

输出格式:

对于每一个查询操作,你应该按照顺序依次输出结果,每个结果占一行。

输入输出样例

输入样例#1:
5 100
A 96
Q 1
A 97
Q 1
Q 2
输出样例#1:
96
93
96

说明

[JSOI2008]

思路1:因为每次都只要末尾几个数中的最大值,考虑用单调栈维护。

#include<iostream>  
#include<cstring>  
#include<cstdio>   
using namespace std;  
int M,D,t=0; 
int size;  
int a[200500];  
int num[200500];  
int main()  
{  
    int Ln,len=0;  
    char QA[5];  
    scanf("%d%d", &M, &D);  
    while(M--)  
    {  
        scanf("%s %d", QA, &Ln); 
        if(QA[0] == 'A')
        {  
            Ln=(Ln+t)%D;  
            num[++len]=Ln;//每次加入一个Ln,num数组长度++ 
            while(size&&num[a[size]]<=Ln) 
                size--;//单调栈操作 
            a[++size]=len;  
        }  
        else 
        {  
            int pos=lower_bound(a+1,a+size+1,len-Ln+1)-a; //二分查找 
            t=num[a[pos]]; 
            cout<<t<<endl;  
        }  
    }  
    return 0;  
}
思路2:线段树当然是可以解决的,只不过用蚊子来打大炮了。。。。

#include<iostream>
#include<cstdio>
using namespace std;
int n,p,t,len,a[200005*4],pos[200005*4];
void build(int x,int l,int r)
{
	a[x]=-1000000000;
	if(l==r){
		pos[l]=x;
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build((x<<1)+1,mid+1,r);
}
void change(int x,int len,int n)
{
	a[pos[len]]=n;
	int tmp=pos[len];
	while(a[tmp]>a[tmp>>1]){
		a[tmp>>1]=a[tmp];
		tmp>>=1;
	}
}
int query(int x,int l,int r,int sj,int tj)
{
	if(l>tj||r<sj) return -10000000;
	if(l>=sj&&r<=tj) return a[x];
	int mid=(l+r)>>1;
	return max(query(x<<1,l,mid,sj,tj),query((x<<1)+1,mid+1,r,sj,tj));
}
int main()
{
	int i,x;
	char flag;
	scanf("%d%d",&n,&p);
	build(1,1,n);
	for(i=1;i<=n;i++){
		cin>>flag;
		cin>>x;
		if(flag=='Q'){
			printf("%d\n",t=query(1,1,n,len-x+1,len));
		}
		else change(1,++len,(x+t)%p);
	}
} 
此外,用树状数组也可以解决,不过yu处理比较麻烦,因为问的是最后几个数,而树状数组维护的是前几个数,所以需要反向读入。

设原数列为c,树状数组为a.

(实际编程时c是用不到的)

a中存最大值

先算出数列总长len。

建立树状数组的时候反向建立。

num存数列为空的长度,

即a[1]到a[num]为-maxlongint,a[num+1]到a[len]存有数据。

对于Q操作,即求c[1]到c[num+L]的最大值

对于A操作,在c[num]处更新。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=200005;
int n,p,t,len,a[MAXN*4],b[3][MAXN];
int Lowbit(int x)
{
	return x&(-x); 
}
void change(int n,int x)
{
	while(n<=len){
		a[n]=max(a[n],x);
		n+=Lowbit(n);
	}
}
int  query(int x)
{
	int ans=-100000000;
	while(x>0){
		ans=max(ans,a[x]);
		x-=Lowbit(x);
	}
	return ans;
}
int main()
{
	int i,num;
	char flag;
	scanf("%d%d",&n,&p);
	for(i=1;i<=n;i++){
		cin>>flag>>b[2][i];
		if(flag=='A'){
			b[1][i]=2;
			b[2][i]%=p;
			len++;
		}
		else{
			b[1][i]=1;
		}
	}
	num=len;
	memset(a,128,sizeof(a));
	for(i=1;i<=n;i++){
		if(b[1][i]==1){
			printf("%d\n",t=query(num+b[2][i]));
		}
		else{ 
			change(num,(b[2][i]+t)%p);
			num--;
		}
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用[1],dp[u][j]表示在u子树中选取恰好j个人时能获得的最大价值。而根据引用,该问题的时间复杂度为O(log2​104×nm)。 对于P2143 [JSOI2010] 巨额奖金问题,我们可以使用动态规划来解决。具体步骤如下: 1. 首先,我们需要构建一棵树来表示员工之间的关系。树的根节点表示公司的总经理,其他节点表示员工。每个节点都有一个权值,表示该员工的奖金金额。 2. 接下来,我们可以使用动态规划来计算每个节点的dp值。对于每个节点u,我们可以考虑两种情况: - 如果选择节点u,则dp[u][j] = dp[v][j-1] + value[u],其中v是u的子节点,value[u]表示节点u的奖金金额。 - 如果不选择节点u,则dp[u][j] = max(dp[v][j]),其中v是u的子节点。 3. 最后,我们可以通过遍历树的所有节点,计算出dp[u][j]的最大值,即为所求的巨额奖金。 下面是一个示例代码,演示了如何使用动态规划来解决P2143 [JSOI2010] 巨额奖金问题: ```python # 构建树的数据结构 class Node: def __init__(self, value): self.value = value self.children = [] # 动态规划求解最大奖金 def max_bonus(root, j): dp = [[0] * (j+1) for _ in range(len(root)+1)] def dfs(node): if not node: return for child in node.children: dfs(child) for k in range(j, 0, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-1] + node.value) for child in node.children: for k in range(j, 0, -1): for l in range(k-1, -1, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-l-1] + dp[child.value][l]) dfs(root) return dp[root.value][j] # 构建树 root = Node(1) root.children.append(Node(2)) root.children.append(Node(3)) root.children[0].children.append(Node(4)) root.children[0].children.append(Node(5)) root.children[1].children.append(Node(6)) # 求解最大奖金 j = 3 max_bonus_value = max_bonus(root, j) print("最大奖金为:", max_bonus_value) ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值