Codeforces 460C Present 二分+前缀和

本文介绍了一种使用二分查找解决区间加法问题的方法。对于给定的n个整数和m次操作,每次操作将[i,i+w)区间内的数加1,最终找出经过所有操作后数组中的最大值。通过维护前缀和并利用二分查找来优化算法的时间复杂度。

点击打开链接

题意:n个数,m次操作 n,m<=1e5,操作:每次将[i,i+w)中的数+1,问m次操作后最小值最大为?
二分最值x,判定:res为a[i]过去被累加次数,显然res=[a[i-w+1]~a[i-1]]被累加的次数之和,利用前缀和b[i]记录前i个数累加之和即可求出res 
若a[i]+res<x 则a[i]肯定要操作,更新次数即可. 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
ll n,m,w,a[N];
ll b[N];//前i个数总共被加多少次 
bool check(ll x)
{
	ll cnt=0;
	memset(b,0,sizeof(b));
	for(ll i=1;i<=n;i++)
	{
		ll res=0; 
		b[i]=b[i-1];//
		ll k=max((ll)0,i-w);//
		res=b[i-1]-b[k];//a[i]过去被加了多少次? [i-w+1~i-1]加了多少次 
		if(a[i]+res<x)
			b[i]+=x-(a[i]+res);	
	}
	return b[n]<=m;
}
int main()
{
	while(cin>>n>>m>>w)
	{
		for(int i=1;i<=n;i++)
			scanf("%I64d",&a[i]);
		ll l=1,r=2e10,ans;
		while(l<=r)
		{
			ll mid=(l+r)>>1;
			if(check(mid))
			{
				ans=mid;
				l=mid+1;
			}
			else
				r=mid-1;
		}
		cout<<ans<<endl;
	}
	return 0;
}


# CF1225E Rock Is Push ## 题目描述 你现在在一个$n×m$的迷宫的左上角(即点$(1,1)$),你的目标是到达迷宫的右下角(即点$(n,m)$)。一次移动你只能向右或者是向下移动一个单位。比如在点$(x,y)$你可以移动到点$(x+1,y)$或点$(x,y+1)$ 迷宫中的一些点是岩石,当你移动到一个有岩石的点时岩石将被推到你移动方向的下一个点(你可以把岩石想象成推箱子游戏中的箱子),而如果那个点上也有一个岩石,它就会被按相同方向推的更远,以此类推(比如当前点右边有连着的十块岩石,你向右走一个点这些岩石就都会被向右推一个点) 这个迷宫被不可移动或是摧毁的墙包围着,石头是不允许被推到墙外或者摧毁墙的。(比如你右边有一个石头,而再往右是墙,你就不能往右移动了) 现在,请你计算出有多少种不同的可以到达终点的方案,由于方案数可能很大,结果请对$10^9+7$取模。两条路径中如果有任意的至少一个点不同,那就认为这两种方案是不同的。 ## 输入格式 输入第一行是两个正整数$n,m$,表示迷宫的长和宽$(1≤n,m≤2000)$ 然后有$n$行,每行$m$个字符,如果第$i$行的第$j$个字符是"$R$",那就说明点$(i,j)$存在一块岩石,如果是".",那就说明点$(i,j)$是空的 数据保证出发点$(1,1)$一定是空的 ## 输出格式 输出一个整数,表示从$(1,1)$走到$(n,m)$的方案数对$10^9+7$取模的结果。 ## 输入输出样例 #1 ### 输入 #1 ``` 1 1 . ``` ### 输出 #1 ``` 1 ``` ## 输入输出样例 #2 ### 输入 #2 ``` 2 3 ... ..R ``` ### 输出 #2 ``` 0 ``` ## 输入输出样例 #3 ### 输入 #3 ``` 4 4 ...R .RR. .RR. R... ``` ### 输出 #3 ``` 4 ``` ## 说明/提示 第一个样例中,不需要移动就能到达终点,所以只有一种路径方案,输出$1$ 第二个样例中终点被岩石挡住了,无法到达,所以没有方案可以到达终点,输出$0$ 点击本网址可以看到第三个样例的例图 https://assets.codeforces.com/rounds/1225/index.html #include<bits/stdc++.h> #define md 1000000007 #define int long long using namespace std; int f[2005][2005][2];//0向下,1向右 bool isst[2005][2005]; int xy[2005][2005];//从当前格子右边到边界有多少个空格,不包括当前格子 int xx[2005][2005]; int n,m; main() { // freopen("test.txt","r",stdin); ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>m;//n 行,m 列 for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { char c; cin>>c; if(c=='R') isst[i][j]=1;//第 i 行,第 j 列 } } for(int i=1; i<=n; i++) { for(int j=m-1; j>=1; j--) { xy[i][j]=xy[i][j+1]+1-isst[i][j+1]; } } for(int i=n-1; i>=1; i--) { for(int j=1; j<=m; j++) { xx[i][j]=xx[i+1][j]+1-isst[i+1][j]; } } f[1][1][0]=f[1][1][1]=1; for(int i=1; i<=n; i++) {//0向下,1向右 for(int j=1; j<=m; j++) { if(i==1&&j==1) continue; if(isst[i][j]==0) { f[i][j][0]=f[i-1][j][0]+f[i-1][j][1]; f[i][j][1]=f[i][j-1][1]+f[i][j-1][0]; } else { if(xy[i][j]==0) { f[i][j][1]=0; if(xx[i][j]==0) f[i][j][0]=0; else if(xx[i][j]==1) { if(isst[i][j-1]==1) f[i][j][0]=0; else f[i][j][0]+=f[i][j-1][0]+f[i][j-1][1]; } else f[i][j][0]+=f[i][j-1][0]+f[i][j-1][1]; } else if(xy[i][j]==1) { if(isst[i][j-1]==1) f[i][j][1]=f[i][j-1][0]; else f[i][j][1]+=f[i][j-1][1]+f[i][j-1][0]; if(xx[i][j]==0) f[i][j][0]=0; else if(xx[i][j]==1) { if(isst[i-1][j]==1) f[i][j][0]=0; else f[i][j][0]+=f[i-1][j][0]+f[i-1][j][1]; } else f[i][j][0]+=f[i-1][j][0]+f[i-1][j][1]; } else { f[i][j][1]=f[i][j-1][0]+f[i][j-1][1]; if(xx[i][j]==0) f[i][j][0]=0; else if(xx[i][j]==1) { if(isst[i-1][j]==1) f[i][j][0]=0; else f[i][j][0]+=f[i-1][j][0]+f[i-1][j][1]; } else f[i][j][0]+=f[i-1][j][0]+f[i-1][j][1]; } } f[i][j][1]%=md; f[i][j][0]%=md; } } cout<<(f[n][m][0]+f[n][m][1])/2%md; }
08-30
c++14 ## 题目描述 给定一个由 $n$ 条指令组成的程序,这些指令由一个具有单个整数寄存器 $A$ 的处理器执行,初始值为 $0$。每条指令是以下两种类型之一: - $\texttt{+ v}$ —— 执行 $A := A + v$; - $\texttt{= v}$ —— 执行 $A := v$。 程序中的指令从 $1$ 到 $n$ 编号。每条指令 $i$ 初始时间戳为 $i$。 有些指令被标记为 **异步**。如果指令 $i$ 是异步的,其时间戳可以更改为任何大于 $i$ 的 **实数**。 在所有时间戳调整之后,所有时间戳必须互不相同。处理器随后按时间戳递增的顺序执行指令。 确定在执行所有指令后,考虑所有可能的异步指令时间戳选择,$A$ 可以得到的不同的最终值的数量。 ## 输入格式 第一行包含一个整数 $n$,表示程序中的指令数量($1 \le n \le 2000$)。 接下来的 $n$ 行中,第 $i$ 行描述指令 $i$,包含三个标记。第一个标记是 $\texttt{+}$ 或 $\texttt{=}$,表示指令的类型。第二个标记是一个整数 $v$,表示指令的参数($1 \le v \le 500$)。最后,第三个标记是 $\texttt{async}$(如果指令被标记为异步)或 $\texttt{sync}$(否则)。 ## 输出格式 输出执行程序后 $A$ 可以取到的不同最终值的数量。 ## 输入输出样例 #1 ### 输入 #1 ``` 3 + 1 sync = 2 async + 3 async ``` ### 输出 #1 ``` 2 ``` ## 输入输出样例 #2 ### 输入 #2 ``` 10 = 7 async + 3 async + 5 sync + 3 async = 1 sync + 9 async + 10 async + 1 sync + 3 async + 4 sync ``` ### 输出 #2 ``` 30 ``` ## 说明/提示 在第一个测试中,程序执行从指令 $1$ 将 $A$ 设置为 $1$ 开始。然后,指令 $2$ 和 $3$ 按以下两种顺序之一执行: - 如果 $\texttt{= 2}$ 在 $\texttt{+ 3}$ 之前执行,$A$ 将等于 $5$; - 如果 $\texttt{+ 3}$ 在 $\texttt{= 2}$ 之前执行,$A$ 将等于 $2$。 因此,最后 $A$ 有两个可能的值:$5$ 和 $2$。
最新发布
11-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值