互测4

A. 礼物

每个颜色最多出现在路径里两次于是答案最大为 \(15\)

\(f_{i,x}\) 表示 \(i\) 到 颜色为 \(x\) 的点的最短距离

那么两点距离可以写成 \(\min(i-j,f_{i,c}+f_{j,c}+1)\)

\(g_{x,y}\) 表示颜色为 \(x\) 的点到颜色为 \(y\) 的点的最短距离

那么 \(f_{i,x}\) 要么等于 \(g_{col_x,y}\) 要么等于 \(g_{col_x,y}+1\)

于是可以用个二进制状态表示出来

不难发现状态相同的点可以直接算

于是预处理出 \(v_{x,y,s1,s2}\) 表示颜色为 \(x\) 的点状态为 \(s1\) 颜色为 \(y\) 的点状态为 \(s2\) 时,两点间的最短路距离

然后再暴力求出距离小于 \(15\) 的答案,统计在一起就行

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,a1,a2;
char st[100010];
int v[8][8][256][256],g[8][8],f[100010][8];
int dis[100010],sta[100010],cnt[8][256];
int head[100010],ver[400010],to[400010],edge[400010],tot;
int vis[100010],now;
priority_queue<pair<int,int> > q;
inline void add(int x,int y,int z){ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;}
inline void dij(int col){
	for(int i=1;i<=n+8;i++) dis[i]=inf,vis[i]=0;
	for(int i=1;i<=n;i++) if(st[i]==col) dis[i]=0,q.push(make_pair(0,i));
	while(!q.empty()){
		int x=q.top().second;q.pop();if(vis[x]) continue;vis[x]=1;
		for(int i=head[x];i;i=to[i]){
			int y=ver[i];
			if(dis[y]>dis[x]+edge[i]){
				dis[y]=dis[x]+edge[i];
				q.push(make_pair(-dis[y],y));
			}
		}
	}
	for(int i=1;i<=n;i++) g[col][st[i]]=min(g[col][st[i]],dis[i]);
	for(int i=1;i<=n;i++) f[i][col]=min(dis[i],g[col][st[i]]+1);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("gift.in","r",stdin);
	freopen("gift.out","w",stdout);
	n=read();scanf("%s",st+1);for(int i=1;i<=n;i++) st[i]-='a';memset(g,0x3f,sizeof(g));
	for(int i=1;i<n;i++) add(i,i+1,1),add(i+1,i,1);
	for(int i=1;i<=n;i++) add(i,n+1+st[i],1),add(n+1+st[i],i,0);
	for(int i=0;i<8;i++) dij(i);memset(v,0x3f,sizeof(v));
	for(int i=0;i<8;i++) for(int j=0;j<8;j++) for(int s1=0;s1<256;s1++)
		for(int s2=0;s2<256;s2++) for(int k=0;k<8;k++) 
			v[i][j][s1][s2]=min(v[i][j][s1][s2],g[i][k]+g[j][k]+((s1>>k)&1)+((s2>>k)&1)+1);
	for(int i=1;i<=n;i++){
		for(int j=max(1ll,i-15),d;j<i;j++){
			d=i-j;for(int k=0;k<8;k++) d=min(d,f[i][k]+f[j][k]+1);
			if(d>a1) a1=d,a2=0;if(a1==d) a2++;
		}
		for(int j=0;j<8;j++) sta[i]|=(f[i][j]-g[st[i]][j])<<j;
		for(int j=0;j<8;j++){
			for(int s1=0,d;s1<256;s1++) if(cnt[j][s1]){
				d=v[st[i]][j][sta[i]][s1];
				if(d>a1) a1=d,a2=0;
				if(a1==d) a2+=cnt[j][s1];
			}
		}
		if(i>15) cnt[st[i-15]][sta[i-15]]++;
	}
	printf("%lld %lld\n",a1,a2);
	return 0;
}

B. 循环

不太想写,丢个链接跑路

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define meow(args...) fprintf(stderr,args)
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,x,p;
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%p;base=base*base%p;k>>=1;}
	return res;
}
inline bool ckprime(int x){
	if(x<2) return false;
	for(int i=2;i*i<=x;i++) if(x%i==0) return false;
	return true;
}
inline bool ckrt(int x){
	if(x%p==0) return false;
	for(int i=2;i*i<p;i++) if((p-1)%i==0){
		if(qpow(x,i)==1) return false;
		if(qpow(x,(p-1)/i)==1) return false;
	}
	return true;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("rotatable.in","r",stdin);
	freopen("rotatable.out","w",stdout);
	n=read(),x=read();p=n+1;
	if(!ckprime(p)) puts("-1"),exit(0);
	for(int i=x-1;i>1;i--) if(ckrt(i)) printf("%lld\n",i),exit(0);
	puts("-1"),exit(0);
	return 0;
}

C. 排列

若满足 \(max-min+1=r-l+1\) 则区间合法

我的暴力就是根据这个写的,也是维护那个值,只不过不会这个题的标记

于是用离线下来,用单调队列去维护上面那个东西

因为 \(mx-mn-r+l\) 大于等于 \(0\) ,于是直接维护区间最小值和等于最小值的个数

再引入一个新的标记用来统计答案

因为区间加减时始终满足最小值数量不变以及值大于等于 \(0\)

所以可以用那个标记去求答案,在向儿子传标记时要判断是否等于 \(0\)

实现上写的是和根判断是否相同,因为时刻满足最小值为 \(0\)

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define lson rt<<1
#define rson rt<<1|1
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,q;
int a[120010],ans[120010];
int stk1[120010],stk2[120010],p1,p2;
struct seg{int sum,mn,c,atag,ctag;}st[120010*4];
vector<pair<int,int> >vec[120010];
inline void pushup(int rt){
	st[rt].sum=st[lson].sum+st[rson].sum;
	st[rt].mn=min(st[lson].mn,st[rson].mn);st[rt].c=0;
	if(st[rt].mn==st[lson].mn) st[rt].c+=st[lson].c;
	if(st[rt].mn==st[rson].mn) st[rt].c+=st[rson].c;
}
inline void pushdown(int rt){
	if(st[rt].atag){
		st[lson].atag+=st[rt].atag;st[lson].mn+=st[rt].atag;
		st[rson].atag+=st[rt].atag;st[rson].mn+=st[rt].atag;
		st[rt].atag=0;
	}
	if(st[rt].ctag){
		if(st[lson].mn==st[rt].mn) st[lson].ctag+=st[rt].ctag,st[lson].sum+=st[lson].c*st[rt].ctag;
		if(st[rson].mn==st[rt].mn) st[rson].ctag+=st[rt].ctag,st[rson].sum+=st[rson].c*st[rt].ctag;
		st[rt].ctag=0;
	}
}
void build(int rt,int l,int r){
	if(l==r) return st[rt].mn=l,st[rt].c=1,void();
	int mid=(l+r)>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
	pushup(rt);
}
void upd(int rt,int l,int r,int L,int R,int k){
	if(L<=l&&r<=R) return st[rt].mn+=k,st[rt].atag+=k,void();
	int mid=(l+r)>>1;pushdown(rt);
	if(L<=mid) upd(lson,l,mid,L,R,k);
	if(R>mid) upd(rson,mid+1,r,L,R,k);
	pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
	if(L<=l&&r<=R) return st[rt].sum;
	int mid=(l+r)>>1,res=0;pushdown(rt);
	if(L<=mid) res+=query(lson,l,mid,L,R);
	if(R>mid) res+=query(rson,mid+1,r,L,R);
	return res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("subsegment.in","r",stdin);
	freopen("subsegment.out","w",stdout);
	n=read();for(int i=1;i<=n;i++) a[i]=read();
	q=read();for(int i=1,l,r;i<=q;i++){l=read(),r=read();vec[r].emplace_back(make_pair(l,i));}
	build(1,1,n);
	for(int i=1;i<=n;i++){
		upd(1,1,n,1,n,-1);
		while(p1&&a[stk1[p1]]<a[i]) upd(1,1,n,stk1[p1-1]+1,stk1[p1],a[i]-a[stk1[p1]]),p1--;stk1[++p1]=i;
		while(p2&&a[stk2[p2]]>a[i]) upd(1,1,n,stk2[p2-1]+1,stk2[p2],a[stk2[p2]]-a[i]),p2--;stk2[++p2]=i;
		st[1].ctag++;st[1].sum+=st[1].c;fflush(stdout);
		for(auto L:vec[i]) ans[L.second]=query(1,1,n,L.first,i);
	}
	for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2022-02-24 19:35  Max_QAQ  阅读(59)  评论(0编辑  收藏  举报