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;
}
标签:info,25,ch,const,int,void,ans,2022.7,模拟 来源: https://www.cnblogs.com/into-qwq/p/16518730.html