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