首页 > 其他分享 >POI 四题题解

POI 四题题解

时间:2024-11-15 22:08:54浏览次数:1  
标签:ch const int 题解 四题 tr abs POI nw

P3434 [POI2006] KRA-The Disks

考场上不知道在想什么,把 \(O(n)\) 正解改成 \(O(n \mathrm{log}n)\) 的了。
关于 \(O(n\mathrm{log}n)\) 做法很多,我只讲我的。直接二分盘子会在哪里卡住,二分范围是 \(1\sim lst\)。\(lst\) 表示上一个盘子卡住的位置。

\(\mathrm{Code}\)


#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,lst,k;
int st[20][N],lg[N];
int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
inline void ST(){
	for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=lg[n];++i){
		for(int j=1;j<=n-(1<<i)+1;++j){
			st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
		}
	}
}
inline int Qry(int l,int r){
	int p=lg[r-l+1];
	return min(st[p][l],st[p][r-(1<<p)+1]);
}
inline bool chk(int x){
	return Qry(1,x)>=k;
} 
int main(){
	freopen("kra.in","r",stdin);
	freopen("kra.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;++i)st[0][i]=read();
	ST();lst=n+1;int l,r,mid;
	for(int i=1;i<=m;++i){
		k=read();l=0,r=lst-1;
		while(l<r){
			mid=(l+r+1)>>1;
			if(chk(mid))l=mid;
			else r=mid-1;
		}if(!l){printf("0");return 0;}
		else lst=l;
	}printf("%d",lst);
	return 0;
}

\(O(n)\) 正解就是注意到盘子位置是单调递减的,合法的位置是要满足 \(r_i>=k \ \to f_i>=k\) 所以我们直接维护一个单调的前缀最小,从下向上扫,只要满足 \(f_i \le k\) 就停止扫描。实现有些细节要注意。

\(\mathrm{Code}\)


#include<bits/sdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,k,r[N];
int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int main(){
	n=read(),m=read();r[0]=1e9+1;
	for(int i=1;i<=n;++i)r[i]=read(),r[i]=min(r[i-1],r[i]);
	int lst=n+1;
	for(int i=1;i<=m;++i){
		k=read();
		while(r[lst]<k) --lst;
		--lst;
		if(lst==0){
			printf("0");
			return 0;
		}
	}printf("%d",lst+1);
	return 0;
}

P3459 [POI2007] MEG-Megalopolis

树剖秒了。

\(\mathrm{Code}\)


#include<bits/stdc++.h>
#define ls p<<1
#define rs p<<1|1
using namespace std;
const int N=1e5+5;
int n,m;
int f[N],hs[N],sz[N],top[N],dfn[N],dep[N];
struct E{
	int to,nxt;
}e[N<<1];int hd[N],tot,idx;
inline void Add(int u,int v){
	e[++tot].to=v,e[tot].nxt=hd[u],hd[u]=tot;
}
struct Tr{
	int l,r,val,tag;
}tr[N<<2];
int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
inline void dfs1(int nw,int fa){
	f[nw]=fa;sz[nw]=1;dep[nw]=dep[fa]+1;
	for(int i=hd[nw];i;i=e[i].nxt){
		if(e[i].to!=fa){
			dfs1(e[i].to,nw);
			sz[nw]+=sz[e[i].to];
			if(sz[e[i].to]>sz[hs[nw]]) hs[nw]=e[i].to;
		}
	}
}
inline void dfs2(int nw,int fa){
	dfn[nw]=++idx;top[nw]=fa;
	if(!hs[nw])return;
	dfs2(hs[nw],fa);
	for(int i=hd[nw];i;i=e[i].nxt){
		if(e[i].to!=f[nw]&&e[i].to!=hs[nw]){
			dfs2(e[i].to,e[i].to);
		}
	}
}
inline void Build(const int p,const int l,const int r){
	tr[p].l=l,tr[p].r=r;
	if(l==r){
		if(l!=1)tr[p].val=1;
		return;
	}int mid=(l+r)>>1;
	Build(ls,l,mid),Build(rs,mid+1,r);
	tr[p].val=tr[ls].val+tr[rs].val;
}
inline void Change(const int p,const int val){
	tr[p].val-=(tr[p].r-tr[p].l+1)*val;tr[p].tag+=val;
}
inline void Pushdown(const int p){
	if(!tr[p].tag)return;
	Change(ls,tr[p].tag),Change(rs,tr[p].tag);
	tr[p].tag=0;
}
inline void Mdf(const int p,const int l,const int r){
	if(tr[p].l>=l&&tr[p].r<=r){
		Change(p,1);return;
	}Pushdown(p);
	int mid=(tr[p].l+tr[p].r)>>1;
	if(l<=mid)Mdf(ls,l,r);
	if(mid<r)Mdf(rs,l,r);
	tr[p].val=tr[ls].val+tr[rs].val;
}
inline int Qry(const int p,const int l,const int r){
	if(tr[p].l>=l&&tr[p].r<=r) return tr[p].val;
	Pushdown(p);
	int mid=(tr[p].l+tr[p].r)>>1,res=0;
	if(l<=mid)res+=Qry(ls,l,r);
	if(mid<r)res+=Qry(rs,l,r);
	return res;
}
inline int Path_Q(int v){
	int res=0;
	while(top[v]!=1){
		res+=Qry(1,dfn[top[v]],dfn[v]);
		v=f[top[v]];
	}return res+Qry(1,1,dfn[v]);
}
int main(){
	freopen("meg.in","r",stdin);
	freopen("meg.out","w",stdout);
	n=read();int u,v;char id;
	for(int i=1;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u);
	dfs1(1,0),dfs2(1,1);Build(1,1,n);
	m=read();for(int i=1;i<=n+m-1;++i){
		id=getchar();
		if(id=='A'){
			u=read(),v=read(); 
			Mdf(1,dfn[v],dfn[v]);
		}else{
			v=read();
			printf("%d\n",Path_Q(v));
		}
	}
	return 0;
}
/*
5
1 2
1 3
1 4
4 5
4
W 5
A 1 4
W 5
A 4 5
W 5
W 2
A 1 2
A 1 3

*/

可以不树剖,只借用树剖的思想,把dfn序拉出来,原问题相当于是子树修改单点查询前缀,或者单点修改区间查询,树状数组维护即可。(其实我一开始是这么想的,但是树剖秒了)
或者括号序列。
结论:\(i\) 入栈时栈内的点是 \(1\) 到 \(i\) 的路径上的点。
以 \(1\) 为根进行 \(\mathrm{DFS}\) ,每个点(1除外)入栈时向序列中加一个 \(1\) ,出栈时加入一个 \(-1\) (其实不就是差分吗)。
对于更改 \(E(s,t)\) ,我们将较深点对应的权值变为 \(0\) ;对于询问,设 \(x\) 入栈位置为 \(K\) ,那么 \(1\) 到 \(x\) 的距离为前 \(K\) 个元素的和。
使用树状数组维护即可。

同学的 \(\mathrm{Code}\)


#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> g[250025];
int fa[250025],dep[250025],dfn[250025],all,size[250025];
int cf[250025];
void dfs(int s){
	size[dfn[s]]=1;
	for(int i=0;i<g[s].size();i++){
		int to=g[s][i];
		if(dfn[to]) continue;
		dfn[to]=++all; fa[all]=dfn[s];
		dep[all]=dep[dfn[s]]+1;
		dfs(to);
		size[dfn[s]]+=size[dfn[to]];
	}
} 
int d[250025];
int lowbit(int x){
	return x&(-x);
}
void add(int p,int num){
	while(p<=n){
		d[p]+=num;
		p+=lowbit(p);
	}
}
int getnum(int p){
	int sum=0;
	while(p){
		sum+=d[p];
		p-=lowbit(p);
	}
	return sum;
}
void build(int l,int r){
	for(int i=1;i<=n;i++) cf[i]=dep[i]-dep[i-1];
	for(int i=1;i<=n;i++) add(i,cf[i]);
}
int main(){
	freopen("meg.in","r",stdin);
	freopen("meg.out","w",stdout);
	ios::sync_with_stdio(0);
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dep[1]=0; dfn[1]=++all;
	dfs(1);
	build(1,n);
	cin>>m;
	int T=n+m-1;
	while(T--){
		char op;
		cin>>op;
		if(op=='A'){
			int a,b;
			cin>>a>>b;
			if(dfn[a]<dfn[b]) swap(a,b);
			add(dfn[a],-1);
			add(dfn[a]+size[dfn[a]],1);
		}
		else{
			int a,t;
			int ans=0;
			cin>>a;
			cout<<getnum(dfn[a])<<'\n';
		}
	} 
	return 0;
}

P3457 [POI2007] POW-The Flood 题解

gs题面。你说得对,但是直接判连通块有 20 分,输出 1 甚至有 30 分。

先说明一下抽水的定义:

假设当前有一个抽水机放在 \(i\) 点,若存在一条到 \(j\) 的路径 \(P\)(不包含 \(i,j\) )使得 \(\small \max\limits_{k\in P} h_k \le h_j\),则 \(j\) 点也可以被抽干。每个点的高度是其对应位置数的绝对值。这一点后面重要声明会用到。


非常直接的想法就是选择最低的地方放抽水机,但是在什么地方放呢?

我们是要在抽干城市的水,所以只在城市放是不劣的,这一点很多题解没有说清楚。

考虑反证法,如果有一个低的点 可以使得放在这里 能让这个连通块内的城市全都被抽干,那么一定存在一个城市也可以,因为一定有一个路径 可以通过低的那个点走到其他城市;而如果对于高的点,放抽水机肯定不优。感性理解一下

其实这个可以看一下这篇题解,不是一定放在城市,只是可以。

那么我们的步骤就出来了:

我们将点从小到大排序,并对这个点进行合并操作,维护连通块。如果这个点所在连通块中没有城市且这个点是城市,就放一个抽水机。

一个非常重要的事情我们要申明:

连通块存在的意义是判断当前点的水能不能流到前面判过了的海拔较低的点,是判断一个连通块内的点都可以走到最低的点,而我们的实现是反着的,是判断这个点能不能被周围的点到达。因为我们是从前往后扫,只知道小的点的联通情况,所以这个点与前面的点是被到达的关系(BFS 是正着的)!我们正着思考是如我上面所说的抽水定义来判断的,反着思考虽然因为对称性(应该不叫对称性,姑且一用)是一样的,但是本质上是有区别的。更通俗一点就是我们是根据水能不能从当前点流到最低点来判断能不能被低的点抽到,是判断当前点能否被代表元到达,而不是以当前点为代表元,那样就成了高的点抽低的点的水了

还有一个问题:

由于每次每个点只会在周围四个点向外合并,所以如果一个点被所有相同的海拔包在里面了(虽然高度相同,但是由于排序了,所以不会在一个地方),并查集是会把它们判成不同连通块的的。是出于这个问题才应该将所有海拔相同的合并完,再返回去处理前面的。Hack 数据我借用一下第二篇题解的:

3(1) 3(2) 2(3) 1(4)

括号表示编号。
排完序变成

1 2 3(1) 3(2)

我们从前往后扫,发现第一个 \(3\) 和后面的 \(1,2\) 中间是有一个 \(3\) 隔着的,这个 \(3\) 没有更新。

为什么要这样做,是因为手太短了,一次搜索没有将所有可以并的点都并进来,传递性出了问题,而BFS就没有这个问题。

至于为什么这样是对的,如果两个海拔相同的所在的连通块隔开没有影响,如果两个海拔相同的连通块在一起那么可以合并,也没有影响。

我们可以发现,只有我提到的被相同的包住这种情况会产生,因为如果高了就出不去,低了之前就被合并过。所以不是因为海拔相同出问题,是因为只有海拔相同这个问题才会暴露出来

细节见代码。

这个题的本质见 另一篇题解

\(\mathrm{Code}\)


并查集 好久没写过这么不压行的代码了

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
struct P{
	int x,y,h;
}p[N]; 
int n,m,f[1005][1005];
int fa[N],tag[N],ans;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
inline bool cmp(P A,P B){return abs(A.h)<abs(B.h);}
inline int pos(int x,int y){return m*(x-1)+y;}
inline int find(int x){
	if(fa[x]==x)return x;
	else return fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
	x=find(x),y=find(y);
	if(x==y) return;
	fa[y]=x,tag[x]|=tag[y];//从哪里到,就是哪里的儿子
}
int main(){
	n=read(),m=read();
	for(int i=0;i<=n+1;++i){
		for(int j=0;j<=m+1;++j){
			f[i][j]=1e9+5;
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			p[pos(i,j)].x=i,p[pos(i,j)].y=j;
			f[i][j]=p[pos(i,j)].h=read();
		}
	}
	sort(p+1,p+n*m+1,cmp);
	for(int i=1;i<=n*m;++i) fa[i]=i;
	for(int i=1;i<=n*m;++i){
		if(abs(p[i].h)>=abs(f[p[i].x-1][p[i].y])){
			merge(pos(p[i].x,p[i].y),pos(p[i].x-1,p[i].y));
		}
		if(abs(p[i].h)>=abs(f[p[i].x+1][p[i].y])){
			merge(pos(p[i].x,p[i].y),pos(p[i].x+1,p[i].y));
		}
		if(abs(p[i].h)>=abs(f[p[i].x][p[i].y-1])){
			merge(pos(p[i].x,p[i].y),pos(p[i].x,p[i].y-1));
		}
		if(abs(p[i].h)>=abs(f[p[i].x][p[i].y+1])){
			merge(pos(p[i].x,p[i].y),pos(p[i].x,p[i].y+1));
		}
		if(abs(p[i].h)==abs(p[i+1].h))continue;
		int y;
		for(int j=i;abs(p[j].h)==abs(p[i].h);--j){//对之前所有海拔相同的点都统计 
			if(f[p[j].x][p[j].y]>0){
				y=find(pos(p[j].x,p[j].y));
				if(!tag[y]) tag[y]=1,++ans;
			}
		}
	}
	printf("%d",ans);
	return 0;
}

BFS(同学的)

#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0,sum,all;
int hy[4]={-1,0,1,0};
int zy[4]={0,1,0,-1};
int a[1010][1010];
int num[1010][1010];
int b[1010][1010];
bool book[1010][1010];
struct node{
	int x,y,dat;
};
bool cmp(node t,node q){
	return t.dat<q.dat;
}
vector<node> temp;
void bfs(int x,int y){
	deque<node> q;
	q.push_front((node){x,y,num[x][y]});
	while(!q.empty()){
		node top=q.front(); q.pop_front();
		book[top.x][top.y]=0;
		for(int i=0;i<4;i++){
			int nx=top.x+hy[i];
			int ny=top.y+zy[i];
			if(nx<1||ny<1||nx>n||ny>m) continue;
			if(a[nx][ny]>0&&num[top.x][top.y]>a[nx][ny]) continue;
			int h=max(b[nx][ny],num[top.x][top.y]);
			if(num[nx][ny]>h){
				num[nx][ny]=h;
				if(!book[nx][ny]){
					book[nx][ny]=1;
					if(num[nx][ny]<=num[top.x][top.y]){
						q.push_front((node){nx,ny,num[nx][ny]});
					}
					else q.push_back((node){nx,ny,num[nx][ny]});
					
				}
			}
		}
	}
}
int main(){
//	freopen("pow.in","r",stdin);
//	freopen("pow.out","w",stdout);
	ios::sync_with_stdio(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			if(a[i][j]>0){
				temp.push_back((node){i,j,a[i][j]});
			}
			b[i][j]=abs(a[i][j]);
		}
	}
	memset(num,0x3f,sizeof(num));
	sort(temp.begin(),temp.end(),cmp);
	for(int i=0;i<temp.size();i++){
		int x=temp[i].x,y=temp[i].y,h=temp[i].dat;
		if(num[x][y]<=h) continue;
		ans++; num[x][y]=h;
		bfs(x,y);
	}
	cout<<ans;
	return 0;
}

P3444 [POI2006] ORK-Ploughing

首先可以记搜,然后可以随机化贪心,然后可以退火。
这个贪心确实难想。
考虑最后的形态必然是只剩一行或一列,那么这启发我们以行为主或以列为主来贪心。
这相当于为我们规定了一个优先级,在这个优先级下的贪心才是正确的,因为和最后的子结构是吻合的。
那我们两个都做一遍,是类似的,下面以行优先为例。
那么考虑我们的贪心策略应该是先把行删完,那么我们在过程中一定不能删太多的列,这样不符合结构,对答案不优。或者说,我们一次性删列,把列留到一起删是最优的(我们答案下界正是这样的,只删行或者只删列,这样看起来就是非常优美的)。
但是总有删列的时候,所以我们枚举删多少列,然后每次按照 “上下左右” 的顺序删,取最小则是对的。
具体证明看 Alex_wei 的题解

\(\mathrm{Code}\)


#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e3+5;
int n,m,K,fi[N][N],suml[N][N],sumr[N][N];
int ans=1e9+1;
int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int main(){
	K=read(),m=read(),n=read();
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j)fi[i][j]=read();
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j)sumr[i][j]=sumr[i][j-1]+fi[i][j];
	}
	for(int i=1;i<=m;++i){
		for(int j=1;j<=n;++j)suml[j][i]=suml[j-1][i]+fi[j][i];
	}
	for(int i=1;i<=m;++i){
		int lx=1,ly=1,rx=n,ry=m,ans1=0;
		while(lx<=rx&&ly<=ry){
			++ans1;
			if(sumr[lx][ry]-sumr[lx][ly-1]<=K){++lx;continue;}
			if(sumr[rx][ry]-sumr[rx][ly-1]<=K){--rx;continue;}
			if(suml[rx][ly]-suml[lx-1][ly]<=K&&ly<i){++ly;continue;}
			if(suml[rx][ry]-suml[lx-1][ry]<=K){--ry;continue;} 
			ans1=1e9+1;break;
		}ans=min(ans,ans1);
	}
	for(int i=1;i<=n;++i){
		int lx=1,ly=1,rx=n,ry=m,ans2=0;
		while(lx<=rx&&ly<=ry){
			++ans2;
			if(suml[rx][ly]-suml[lx-1][ly]<=K){++ly;continue;}
			if(suml[rx][ry]-suml[lx-1][ry]<=K){--ry;continue;} 
			if(sumr[lx][ry]-sumr[lx][ly-1]<=K&&lx<i){++lx;continue;}
			if(sumr[rx][ry]-sumr[rx][ly-1]<=K){--rx;continue;}
			ans2=1e9+1;break;
		}ans=min(ans,ans2);
	}printf("%d",ans);
	return 0;
}

标签:ch,const,int,题解,四题,tr,abs,POI,nw
From: https://www.cnblogs.com/mountzhu/p/18548661

相关文章

  • CF1909F1 Small Permutation Problem (Easy Version) 题解
    CF1909F1SmallPermutationProblem(EasyVersion)题解直接莽做显然不好统计。考虑统计每一次\(i\)的变化有多少种方案数来匹配,也就是对\(a\)数组差分。考虑到对于\(a_i\),只有\([1,i]\)里的数会对\(a_i\)有影响。注意到\(p\)形成一个排列,于是我们不妨考虑此时\(p......
  • [题解]P5687 [CSP-S2019 江西] 网格图
    P5687[CSP-S2019江西]网格图简单来说题目就是给定一个\(n\timesm\)的网格图,同行边权相同,同列边权相同,求该网格图的最小生成树。根据Kruskal算法的贪心思想,我们要优先选择权值尽可能小的行,并将这条边应用于尽可能多的列。列方向同理。为了保证最终生成树的连通性,我们显然要......
  • 题解: BZOJ3517 翻硬币
    ProblemLinkBZOJ3517翻硬币题目描述有一个\(n\)行\(n\)列的棋盘,每个格子上都有一个硬币,且\(n\)为偶数。每个硬币要么是正面朝上,要么是反面朝上。每次操作你可以选定一个格子\((x,y)\),然后将第\(x\)行和第\(y\)列的所有硬币都翻面。求将所有硬币都变成同一个面最少......
  • ISCTF比赛PWN题前三题题解
    萌新第一次发布题解,如有错误还请各位大佬指出。本次比赛个人pwn出题情况,还是太菜了,后面四题基本看不懂girlfriend解题思路:利用填充覆盖检查位置,绕过前面admin检查,进入vuln函数,经过动调发现,每次数据存放位置,从而达到提权解题过程存在后门函数read可以读取0x30大小,观察buf......
  • P9870 [NOIP2023] 双序列拓展 题解
    P9870[NOIP2023]双序列拓展题解NOIP2023T3,特殊性质题。什么是特殊性质题?就是题目给出了你极其神秘的性质,从而引导你想出正解。本篇题解将从部分分的角度,一步步讲述部分分与正解的关系。这样看的话,本题会变得十分简单。\(\text{Task}1∼7,O(Tnm)\)简化题意其实就是要求......
  • Toyota Programming Contest 2024#11(AtCoder Beginner Contest 379)题解总结
    AtCoderBeginnerContest379Rated:\(770\)A-Cyclic简单模拟。B-Strawberries字符串模拟,substr函数秒了C-Repeating中等模拟。思路:判断是否合法很简单,重点在计算花费。假设我们是\(0\)号点有\(N\)个棋子,然后移动到每个点上,显然花费为\(\frac{N(N+1)}{......
  • [CEOI2023] The Ties That Guide Us 题解
    Description你用销售机器人的利润雇佣了一名助手,现在你准备好去拿走装有CEOI奖章的保险箱了。保险箱位于一所由\(n\)个房间所组成的大学建筑内,这些房间由\(n-1\)扇门连接。每个房间都可以从其他任何房间到达,且每个房间最多与\(3\)扇门相连。你和你的助手都有描述建筑物......
  • P1437 敲砖块 题解
    题意在一个凹槽中放置了\(n\)层砖块、最上面的一层有\(n\)块砖,从上到下每层依次减少一块砖。每块砖都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示:14154323333376221311222331如果你想敲掉第\(i\)层的第\(j\)块砖的话,若\(i=1\),你可以直接......
  • [CEOI2023] Tricks of the Trade 题解
    Description有\(n\)个机器人排成一排,第\(i\)个机器人的购买价是\(a_i\)欧元,卖出价是\(b_i\)欧元。给定\(1\lek\len\),你需要购买一段长度至少为\(k\)的区间中所有的机器人,然后选择其中的恰好\(k\)个机器人来卖出。你需要求出:你能够得到的最大收益;在收益最大化......
  • P11276 第一首歌 题解
    P11276第一首歌题解一道简单的字符串题目。题目解释说求一个最短的字符串\(t\),使其满足对于给定的字符串\(s\):\(s\)为\(t\)的前缀。\(s\)为\(t\)的后缀。\(s\)不为\(t\)。仔细思考一下,则易得\(t\)的最短长度的最大值为\(s\)的两倍。即当\(s\)......