省选模拟(chuxiaoxiao)

好难啊,啥也不会,思路很妙的样子,但是不具有普适性,但总体来说是套好题

尤其是第三题,可以说是给出了一类题的解题方案!!

第一题,考场上看了一眼就知道是个特殊性质优化的最短路,然而不知道具体咋做...

第二题,想到了一个\(\mathcal{O(b^2n)}\)的暴力,然而和爆搜一个分!/愤怒

第三题,只会一个莫队,想要维护端点值但是不会

T1 礼物(CF718E)

考虑最短路的类型,只有两种一种是跨越同色边的,一种是不跨越同色边的

跨越同色边的可以用跨越的是哪个颜色的边来统计,不跨越的直接下标相减

考场上的思路终止于这里,因为认为跨越的有可能在不跨越的地方统计了,然而那样的话答案只会更大

然后考虑如何优化,发现一个点到某一个颜色的任意一个点的距离只会是两个颜色之间的最短路或者是最短路+1

于是我们可以将+1标记成1,不+1的标记成0,状压一下就很对了,复杂度稍微有些搞,所以是0的地方可以适当剪枝

AC_code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=1e5+5;
int n,a[N],m;char ch[N];
int ds[N][10],bs[10][10];
vector<int> vec[10];
queue<int> q;
int lsh[N],lh;
bool vis[N],cvs[10];
ll sm[9][9][1<<8][1<<8],ans,sum;
int su[9][1<<8],dis[9][9][1<<8][1<<8],zt[N];
signed main(){
	memset(dis,0x3f,sizeof(dis));
	memset(ds,0x3f,sizeof(ds));
	memset(bs,0x3f,sizeof(bs));
	n=read();scanf("%s",ch+1);
	fo(i,1,n)a[i]=ch[i]-'a'+1,lsh[++lh]=a[i];
	sort(lsh+1,lsh+n+1);lh=unique(lsh+1,lsh+lh+1)-lsh-1;
	fo(i,1,n)a[i]=lower_bound(lsh+1,lsh+lh+1,a[i])-lsh;m=lh;
	fo(i,1,n)vec[a[i]].push_back(i);
	ans=1;fo(i,1,m)sum+=1ll*vec[i].size()*((int)vec[i].size()-1)/2;
	fo(nn,1,m){
		memset(vis,false,sizeof(vis));
		memset(cvs,false,sizeof(cvs));
		for(int i:vec[nn])q.push(i),vis[i]=true,ds[i][nn]=0;
		while(!q.empty()){
			int x=q.front();q.pop();
			if(!cvs[a[x]]){
				for(int i:vec[a[x]])if(!vis[i])ds[i][nn]=ds[x][nn]+1,q.push(i),vis[i]=true;
				bs[nn][a[x]]=ds[x][nn];
			}
			cvs[a[x]]=true;
			if(x-1>0&&!vis[x-1])ds[x-1][nn]=ds[x][nn]+1,q.push(x-1),vis[x-1]=true;
			if(x+1<=n&&!vis[x+1])ds[x+1][nn]=ds[x][nn]+1,q.push(x+1),vis[x+1]=true;
		}
	}
	int u=(1<<m)-1;
	fo(i,1,m)fo(j,1,m)fo(s,0,u)fo(t,0,u){
		int mn=0x3f3f3f3f;
		fo(k,1,m)mn=min(mn,bs[i][k]+bs[j][k]+(s>>k-1&1)+(t>>k-1&1)+1);
		dis[i][j][s][t]=mn;
		//if(!s&&!t)cerr<<i<<" "<<j<<" "<<dis[i][j][s][t]<<endl;
	}
	fo(i,1,n){
		fo(nn,1,m)zt[i]|=(ds[i][nn]-bs[a[i]][nn])<<(nn-1);//cerr<<"ZZ"<<" "<<i<<" "<<ds[i][nn]<<" "<<bs[a[i]][nn]<<endl;
		fo(nn,1,m)fo(t,0,u)if(su[nn][t]){
			//cerr<<i<<" "<<nn<<endl;
			sm[a[i]][nn][zt[i]][t]+=su[nn][t];
			sm[nn][a[i]][t][zt[i]]+=su[nn][t];
		}
		su[a[i]][zt[i]]++;
		fo(j,1,2*m-1)if(i-j>0&&dis[a[i]][a[i-j]][zt[i]][zt[i-j]]>j){
			sm[a[i]][a[i-j]][zt[i]][zt[i-j]]--;
			if(j>ans)ans=j,sum=1;
			else if(j==ans)sum++;
			if(a[i]!=a[i-j]||zt[i]!=zt[i-j])sm[a[i-j]][a[i]][zt[i-j]][zt[i]]--;
		}
	}
	fo(i,1,m)fo(j,i+1,m)fo(s,0,u)fo(t,0,u)if(sm[i][j][s][t]){
		//cerr<<"SB"<<endl;
		if(dis[i][j][s][t]>ans)ans=dis[i][j][s][t],sum=sm[i][j][s][t];
		else if(dis[i][j][s][t]==ans)sum+=sm[i][j][s][t];
	}printf("%lld %lld",ans,sum);
}

T2 循环(CF303D)

这个题嘛,我认为是化式子的题,于是列了一堆等式然而没有什么蛋用...

暴力的思路就是我可以枚举这个循环串的最后一位是x,因为所有乘法之后得到的是不重复的,所以我们对x乘1~n倍,就可以得到循环串中的所有数字,然后排个序,这样数字之间的对应关系就有了!!直接找到这个序列,判断就好了,复杂度\(\mathcal{O(b^2n)}\)

暴力40
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=5e6+5;
const int mod=1e9+7;
int ksm(int x,int y){
	int ret=1;
	while(y){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;y>>=1;
	}return ret;
}
int n,m;
int num[N],cn,sc[N],so[N];
map<int,int> mp;
bool ck(int b,int x){
	mp.clear();int now=1;
	fo(i,1,n)so[i]=sc[i]=i*x%b;
	sort(so+1,so+n+1);
	fo(i,1,n)mp[sc[i]]=so[i];
	num[1]=so[1];//cerr<<num[1]<<" ";
	fo(i,2,n)num[i]=mp[num[i-1]];//cerr<<num[i]<<" ";cerr<<endl;
	sc[1]=0;fu(i,n,1)sc[1]=(sc[1]+num[i]*now)%mod,now=now*b%mod;
	now=ksm(b,n-1);
	fo(i,2,n)sc[i]=((sc[i-1]-num[i-1]*now%mod+mod)%mod*b%mod+num[i-1])%mod;//cerr<<sc[i]<<" ";cerr<<endl;
	sort(sc+1,sc+n+1);
	fo(i,2,n)if(sc[1]*i%mod!=sc[i])return false;
	return true;
}
signed main(){
	freopen("rotatable.in","r",stdin);
	freopen("rotatable.out","w",stdout);
	//cerr<<(sizeof(num)*3>>20)<<endl;
	n=read();m=read();
	if(n==1){printf("%lld",m-1>1?m-1:-1);return 0;}
	//cerr<<ck(10,7)<<endl;return 0;
	while(m--){if(m==1)continue;
		fu(i,m-1,1)if(ck(m,i)){
			printf("%lld",m);return 0;
		}
	}
	printf("-1");
	return 0;
}

正解是不断的找等价关系,首先写成无限循环小数的形式,然后等等等等,最后就把答案等成了n+1的最大的满足原根性质的数......

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=5e6+5;
const int R=5e6+1;
int ksm(int x,int y,int mod){
	int ret=1;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		x=1ll*x*x%mod;y>>=1;
	}return ret;
}
int n,m,k;
int p[N],mn[N],cnt;bool vis[N];
int pc[100],cpc;
void pre(){
	fo(i,2,R){
		if(!vis[i])p[++cnt]=i,mn[i]=cnt;
		for(int j=1;j<=cnt&&i*p[j]<=R;j++){
			vis[i*p[j]]=true;mn[i*p[j]]=j;
			if(i%p[j]==0)break;
		}
	}
}
void find(){
	fo(i,1,cnt)if((k-1)%p[i]==0)pc[++cpc]=p[i];
}
bool ck(int x){
	fo(i,1,cpc)if(ksm(x,(k-1)/pc[i],k)==1)return false;
	return true;
}
bool isp(int x){
	if(x==2||x==3||x==5)return true;
	if(ksm(2,x-1,x)!=1)return false;
	if(ksm(3,x-1,x)!=1)return false;
	if(ksm(5,x-1,x)!=1)return false;
	return true;
}
signed main(){
	freopen("rotatable.in","r",stdin);
	freopen("rotatable.out","w",stdout);
	n=read();m=read();k=n+1;pre();find();
	if(!isp(k)){printf("-1");return 0;}
	while(m--)if(m>1&&ck(m)){printf("%d",m);return 0;}
	printf("-1");
}

T3 排列(CF997E)

所以这种可以离线的题就直接离线就好了,离了肯定比不离好做......

按照右端点排序,于是我们每次在线段树上维护以当前结点为右端点的所有左端点是否符合条件

发现这样只能维护当前的值,并不能找到子区间的答案,但是想到子区间的右端点在之前已经处理过了,于是想到要记录历史上的贡献

这个东西的pushdown很奇妙,也不能说是奇妙,只能说是充分利用了pushdown的性质

pushdown保证了在下放标记之前,区间内的值是不被更改的

所以我们维护的最小值个数是根本不会改变的,和父亲区间的最小值的大小关系也是不变的

历史标记是否pushdown就看子区间的最小值和父区间是否相同就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
	int s=0,t=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*t;
}
const int N=120005;
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	int mn[N*4],sn[N*4],tg[N*4],sm[N*4],tm[N*4];
	void pushup(int x){
		mn[x]=min(mn[ls],mn[rs]);sn[x]=0;
		if(mn[x]==mn[ls])sn[x]+=sn[ls];
		if(mn[x]==mn[rs])sn[x]+=sn[rs];
		sm[x]=sm[ls]+sm[rs];
	}
	void pushdown(int x){
		if(tg[x]){
			mn[ls]+=tg[x];tg[ls]+=tg[x];
			mn[rs]+=tg[x];tg[rs]+=tg[x];
			tg[x]=0;
		}
		if(tm[x]){
			if(mn[ls]==mn[x])tm[ls]+=tm[x],sm[ls]+=tm[x]*sn[ls];
			if(mn[rs]==mn[x])tm[rs]+=tm[x],sm[rs]+=tm[x]*sn[rs];
			tm[x]=0;
		}
	}
	void build(int x,int l,int r){
		if(l==r)return sn[x]=1,void();
		int mid=l+r>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		pushup(x);
	}
	void ins_tg(int x,int l,int r,int ql,int qr,int v){
		if(ql>qr)return ;
		if(ql<=l&&r<=qr){tg[x]+=v;mn[x]+=v;return ;}
		int mid=l+r>>1;if(tg[x]||tm[x])pushdown(x);
		if(ql<=mid)ins_tg(ls,l,mid,ql,qr,v);
		if(qr>mid)ins_tg(rs,mid+1,r,ql,qr,v);
		pushup(x);
	}
	void ins_tm(int x,int l,int r,int ql,int qr){
		if(ql>qr)return ;
		if(ql<=l&&r<=qr){if(mn[x]==0){sm[x]+=sn[x];tm[x]++;}return ;}
		int mid=l+r>>1;if(tg[x]||tm[x])pushdown(x);
		if(ql<=mid)ins_tm(ls,l,mid,ql,qr);
		if(qr>mid)ins_tm(rs,mid+1,r,ql,qr);
		pushup(x);
	}
	int query(int x,int l,int r,int ql,int qr){
		if(ql>qr)return 0;
		if(ql<=l&&r<=qr)return sm[x];
		int mid=l+r>>1,ret=0;if(tg[x]||tm[x])pushdown(x);
		if(ql<=mid)ret+=query(ls,l,mid,ql,qr);
		if(qr>mid)ret+=query(rs,mid+1,r,ql,qr);
		pushup(x);return ret;
	}
	#undef ls
	#undef rs
}xds;
int n,m,a[N],ans[N];
int stx[N],tx,stn[N],tn;
struct Q{int l,r,id;}q[N];
bool com(Q a,Q b){return a.r==b.r?a.l>b.l:a.r<b.r;}
signed main(){
	freopen("subsegment.in","r",stdin);
	freopen("subsegment.out","w",stdout);
	n=read();
	fo(i,1,n)a[i]=read();
	m=read();
	fo(i,1,m)q[i].l=read(),q[i].r=read(),q[i].id=i;
	sort(q+1,q+m+1,com);
	xds.build(1,1,n);
	fo(i,1,m){
		fo(j,q[i-1].r+1,q[i].r){
			while(tx&&a[stx[tx]]<a[j]){
				xds.ins_tg(1,1,n,stx[tx-1]+1,stx[tx],a[j]-a[stx[tx]]);tx--;
			}stx[++tx]=j;
			while(tn&&a[stn[tn]]>a[j]){
				xds.ins_tg(1,1,n,stn[tn-1]+1,stn[tn],a[stn[tn]]-a[j]);tn--;
			}stn[++tn]=j;
			xds.ins_tg(1,1,n,1,j-1,-1);
			xds.ins_tm(1,1,n,1,j);
			//cerr<<j<<" "<<xds.query(1,1,n,1,1)<<endl;
		}
		ans[q[i].id]=xds.query(1,1,n,q[i].l,q[i].r);
	}
	fo(i,1,m)printf("%lld\n",ans[i]);
}
posted @ 2022-02-24 19:47  fengwu2005  阅读(98)  评论(1)    收藏  举报