Loading

2022.7.25 模拟赛

2022.7.25 模拟赛

题及题解

旅行日记

这题是个简单的贪心,显然我们在两天之间先往上走再往下走

那么对于相邻两天 \(i,j\),我们可以抽象成先花费 \(|h_i-h_j|\) 的时间使两座山的高度都变成高的那座的高度,然后高度可以增加剩下的时间除以 \(2\) (因为要上去再下来)

答案就是 \(\max(h_i,h_j)+(|i-j|-|h_i-h_j|)/2\)

注意要特判无解的情况,和两个边界的情况

#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,m,ans;
struct node{
	int id,h;
	inline bool operator <(const node x) const{
		return id<x.id;
	}
}a[N];

signed main(){
	n=read(),m=read();
	for(int i=1;i<=m;++i){
		a[i].id=read(),a[i].h=read();
	}
	sort(a+1,a+m+1);
	bool f=0;
	for(int i=1;i<=m;++i){
		if(i>1&&abs(a[i].h-a[i-1].h)>a[i].id-a[i-1].id) f=1;
		ans=max(ans,max(a[i].h,a[i-1].h)+(a[i].id-a[i-1].id-abs(a[i].h-a[i-1].h))/2);
	}
	ans=max(ans,a[m].h+(n-a[m].id));
	ans=max(ans,a[1].h+a[1].id-1);
	if(f) puts("IMPOSSIBLE");
	else printf("%d",ans);
}

运动

显然我们要维护一段连续的数使得其中的任意两个数 \(a_i,a_j\) 满足 \(|a_i-a_j|\le k\)

这个东西显然可以用单调队列维护

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;

const int N=3e6+5;

#define lowbit(x) x&-x

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n,k;
int a[N],c[N],b[N];

struct node{
	int x,id;
};

deque <node> q1,q2;

inline void add(int x,int k){
	for(;x<=n;x+=lowbit(x))
		c[x]+=k;
}

inline int query(int x){
	int res=0;
	for(;x;x-=lowbit(x))
		res+=c[x];
	return res;
}

inline void init(){
	int cnt=1;
	sort(b+1,b+n+1);
	for(int i=2;i<=n;++i)
		if(b[i]!=b[i-1]) b[++cnt]=b[i];
	for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b+1;
}

signed main(){
	k=read(),n=read();
	for(int i=1;i<=n;++i) a[i]=read(),b[i]=a[i];
	int l=1,r=1,ans=1;
	q1.push_back({a[1],1});q2.push_back({a[1],1});
	while(r<n){
		int x=a[++r];
		//cout<<r<<" "<<q1.back().x<<" "<<q1.back().id<<" "<<q2.back().x<<" "<<q2.back().id<<endl;
		while(!q2.empty()&&(abs(q2.front().x-x)>k||q2.front().id<l)){
			l=max(l,q2.front().id+1);
			q2.pop_front();
		}
		while(!q1.empty()&&(abs(x-q1.front().x)>k||q1.front().id<l)){
			l=max(l,q1.front().id+1);
			q1.pop_front();
		}
		while(!q1.empty()&&q1.back().x<=x) q1.pop_back();
		q1.push_back({x,r});
		while(!q2.empty()&&q2.back().x>=x) q2.pop_back();
		q2.push_back({x,r});
		//cout<<l<<" "<<r<<endl;
		ans=max(ans,r-l+1);
	}
	printf("%d\n",ans);
}

回文

这题就相当于给你 \(n\) 组区间 \([l,r]\)\(m\) 组询问每次给你两个数 \(x,y\)

问有多少对 \([l,r]\) 满足 \(x\le l\le r\le y\)

由于考场上 \(sb\) 了没有想到二维数组,所以用的离线树状数组

显然我们先按 \(l\) 从大到小排序,从大到小枚举 \(x\),将所有满足 \(l\ge x\)\(r\) 插进树状数组

这样每次查询区间 \([1,y]\) 的和就行了

考后自己造了一组数据然后不吸氧过不了 \(qaq\)

#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;

const int N=5e3+5;
const int M=1e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

struct node{
	int x,y;
	inline bool operator <(const node A) const{
		return x==A.x?y<A.y:x>A.x;
	}
}c[N*N];

struct QRY{
	int x,y,id;
	inline bool operator <(const QRY A) const{
		return x==A.x?y<A.y:x>A.x;
	}
}Q[M];

int n,m,q,cnt;
char s[N],t[2*N];
int p[2*N],ans[M],d[N*N];

inline void add(int x,int k){
	for(;x<=n;x+=(x&-x))
		d[x]+=k;
}
inline int query(int x){
	int res=0;
	for(;x;x-=(x&-x))
		res+=d[x];
	return res;
}

inline void init(){
	for(int i=1;i<=n;++i){
		t[i*2-1]='#';
		t[i*2]=s[i];
	}
	t[0]='%',t[m=2*n+1]='#',t[m+1]='$';
}
inline void manacher(){
	int mr=1,mid=1;
	for(int i=1;i<=m;++i){
		p[i]=min(p[mr-i],p[mid*2-i]);
		for(;i-p[i]>=1&&i+p[i]<=m&&t[i+p[i]]==t[i-p[i]];++p[i]);
		if(i+p[i]>=mr){
			mr=i+p[i];
			mid=i;
		}
	}
	for(int i=2;i<m;++i){
		if(i%2==1&&p[i]==1) continue;
		int x=(i-p[i]+2)/2,y=(i+p[i]-2)/2;
		int nowx=(x+y)/2;
		if((x+y)%2==0){
			for(int j=0;nowx-j>=x;++j){
				c[++cnt]={nowx-j,nowx+j};
			}
		}
		else{
			int nowy=nowx+1;
			for(int j=0;nowx-j>=x;++j){
				c[++cnt]={nowx-j,nowy+j};
			}
		}
	}
}

signed main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	init();
	manacher();
	q=read();
	sort(c+1,c+cnt+1);
	for(int i=1;i<=q;++i){
		Q[i].x=read(),Q[i].y=read();
		Q[i].id=i;
	}
	sort(Q+1,Q+q+1);
	int nowl=1;
	for(int i=1;i<=q;++i){
		while(nowl<=cnt&&c[nowl].x>=Q[i].x){
			add(c[nowl++].y,1);
		}
		ans[Q[i].id]=query(Q[i].y);
	}
	for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
}

基因进化

考虑对于两个相邻的可以交换的位置 \(i,j\ (i<j)\),前 \(j\) 个的最小值只可能是:

  • \(i\) 个数翻转后的最小值 \(b_{1\sim i}\) + 原数组中 \(a_{i+1\sim j}\)

  • \(a_{i+1\sim j}\) 翻转 + 前 \(i\) 个数翻转之后的最小值 \(b_{1\sim i}\)(相当于我同时翻转 \(i,j\)

考虑可以搞一个前缀 \(hash\) 和一个后缀 \(hash\) 来判断它们谁应该放在前面

可以用双端队列维护

具体细节看代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
const int MAXM = 6e5 + 9;
const int Mod = 998244353;
const int P = 1e9 + 7;
const int Q = 1e9 + 9;
const int GP = 10001;
const int GQ = 10005;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct info {int x, y; };
int power(int x, int y, int P) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2, P);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
info operator + (info a, info b) {
	info ans;
	ans.x = (a.x + b.x >= P) ? (a.x + b.x - P) : (a.x + b.x);
	ans.y = (a.y + b.y >= Q) ? (a.y + b.y - Q) : (a.y + b.y);
	return ans;
}
info operator - (info a, info b) {
	info ans;
	ans.x = (a.x - b.x >= 0) ? (a.x - b.x) : (a.x - b.x + P);
	ans.y = (a.y - b.y >= 0) ? (a.y - b.y) : (a.y - b.y + Q);
	return ans;
}
info operator * (info a, int b) {
	info ans;
	ans.x = 1ll * a.x * b % P;
	ans.y = 1ll * a.y * b % Q;
	return ans;
}
info operator * (info a, info b) {
	info ans;
	ans.x = 1ll * a.x * b.x % P;
	ans.y = 1ll * a.y * b.y % Q;
	return ans;
}
bool operator == (info a, info b) {
	return a.x == b.x && a.y == b.y;
}
info base, powb[MAXM];
info invb, powi[MAXM], sum[MAXM];
void update(int &x, int y) {
	x += y;
	if (x >= Mod) x -= Mod;
}
bool mark[MAXN];
int n, m, l, r, ans[MAXM];
int a[MAXN], powk[MAXN];
void popback() {
	r--;
}
void popfront() {
	l++;
}
void pushback(int x) {
	ans[++r] = x;
	sum[r] = sum[r - 1] + powb[r] * x;
}
void pushfront(int x) {
	ans[--l] = x;
	sum[l - 1] = sum[l] - powb[l] * x;
}
bool cmp(int s, int t, int len) {
	int l = 0, r = len;
//	cerr << len << endl; 
	while (l < r) {
		int mid = (l + r + 1) / 2;
		if ((sum[s + mid - 1] - sum[s - 1]) == (sum[t + mid - 1] - sum[t - 1]) * powb[s - t]) l = mid;
		else r = mid - 1;
	}
	if (l == len || ans[s + l] < ans[t + l]) return true;
	else return false;
}
int main() {

	powb[0] = powi[0] = (info) {1, 1};
	base = (info) {GP, GQ};
	invb = (info) {power(GP, P - 2, P), power(GQ, Q - 2, Q)};
	for (int i = 1; i < MAXM; i++) {
		powb[i] = powb[i - 1] * base;
		powi[i] = powi[i - 1] * invb;
	}
	powk[0] = 1;
	for (int i = 1; i < MAXN; i++)
		powk[i] = 37ll * powk[i - 1] % Mod;
	int T; read(T);
	for (int t = 1; t <= T; t++) {
	//	printf("Case %d: ", t);
		read(n), read(m);
		for (int i = 1; i <= n; i++)
			read(a[i]), mark[i] = false;
		for (int i = 1; i <= m; i++) {
			int x; read(x);
			mark[x] = true;
		}
		ans[l = r = MAXN] = a[1];
		sum[l - 1] = (info) {0, 0};
		sum[l] = powb[l] * a[1];
		int last = 1;
		for (int i = 2; i <= n; i++)
			if (!mark[i]) {
				int len = i - last;
				int x = l, length = r - l + 1;
				for (int j = last + 1; j <= i; j++) {
					pushback(a[j]);
					pushfront(a[j]);
				}
				int y = l;
			//	cerr << length << endl;
				if (cmp(x, y, length + len)) {
					while (len--) popfront();
				} else {
					while (len--) popback();
				}
				last = i;
			}
		while (last != n) pushback(a[++last]);
		int final = 0;
		for (int i = l; i <= r; i++)
			update(final, 1ll * powk[i - l] * ans[i] % Mod);
		writeln(final);
	}
	return 0;
}
posted @ 2022-07-25 20:29  Into_qwq  阅读(29)  评论(0编辑  收藏  举报