ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022.7.25 模拟赛

2022-07-25 20:34:10  阅读:130  来源: 互联网

标签:info 25 ch const int void ans 2022.7 模拟


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;
}

标签:info,25,ch,const,int,void,ans,2022.7,模拟
来源: https://www.cnblogs.com/into-qwq/p/16518730.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有