10.3-CSP-S模拟16

这场除了套路题就是科技题非常无语

T1 菜道路

赛时写的\(n^4\)暴力过掉了,好卡但也不好卡,正解就是把枚举边直接换成Floyd判就是\(n^3\)的了

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
#define int ll
using namespace std;

const int maxn=3e2+10;

int dis[maxn][maxn];
int now[maxn][maxn];
int n;
ll ans=0;
struct EDGE{
	int x,y,dis;
	bool operator <(const EDGE & rhs)const{return dis<rhs.dis;}
};
vector<EDGE>vec;

void solve(){
	cin>>n;
	Rep(i,1,n)Rep(j,1,n)cin>>dis[i][j];
	Rep(k,1,n)Rep(i,1,n)if(i!=k)Rep(j,1,n)if(i!=j && j!=k)
	if(dis[i][k]+dis[k][j]<dis[i][j])
		return cout<<"-1\n",void();
	Rep(i,1,n)Rep(j,i+1,n)vec.push_back(EDGE{i,j,dis[i][j]});
	sort(vec.begin(),vec.end());
	memset(now,0x3f,sizeof(now));
	Rep(i,1,n)now[i][i]=0;
	for(auto it : vec){
		if(now[it.x][it.y]==dis[it.x][it.y])continue;
		ans+=it.dis;
		now[it.x][it.y]=now[it.y][it.x]=it.dis;
		Rep(i,1,n)Rep(j,1,n)
		now[i][j]=min(now[i][j],min(now[i][it.x]+it.dis+now[it.y][j],now[i][it.y]+it.dis+now[it.x][j]));
	}
	cout<<ans<<"\n";
}

#undef int
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


T2 简单环

套路建搜索树,只会出现返祖边,一组边有贡献当且仅当他们被同一条返祖边恰好覆盖了一次,树上差分判一下就是\(O(n)\)的,可以开到\(1e6\)

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=1e5+10,maxm=5e5+10;

int n,m;

map<pii,int>Map;

vector<int>ans;

struct Graph{
	struct eg{int from,to,next;}e[maxm];
	int len,head[maxn];int fa[maxn];
	int Root;
	vector<int>son[maxn],gr[maxn];
	void lqx(int from,int to)
	{ e[++len].from=from,e[len].to=to,e[len].next=head[from],head[from]=len; }
	int pre[maxn],val[maxn]; bool vis[maxn];int dep[maxn];
	void Dfs1(int u,int f){
		vis[u]=true;dep[u]=dep[f]+1;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;if(v==f)continue;
			if(!vis[v])Dfs1(v,u),val[u]+=val[v],son[u].push_back(v),fa[v]=u;
			else if(dep[u]>dep[v])
				val[u]++,val[v]--,gr[u].push_back(v);
		}
	}
	void Dfs2(int u){
		pre[u]=(val[u]==1)+pre[fa[u]];
		for(auto v : gr[u])if(pre[u]-pre[v]==dep[u]-dep[v]){
			ans.push_back(Map[minmax(u,v)]);
			int now=u,pt=fa[u];
			while(now!=v){ ans.push_back(Map[minmax(now,pt)]); now=pt,pt=fa[pt]; }
		}
		for(auto v : son[u])Dfs2(v);
	}
}G;

void solve(){
	cin>>n>>m;int x,y;
	Rep(i,1,m){ cin>>x>>y; G.lqx(x,y),G.lqx(y,x);Map[minmax(x,y)]=i; }
	Rep(i,1,n)if(!G.vis[i]){ G.Dfs1(i,0);G.Dfs2(i); }
	cout<<ans.size()<<"\n";
	sort(ans.begin(),ans.end());
	for(auto it : ans)cout<<it<<" ";
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }

T3 汉明距离

科技题,考虑如果算出不同的两位的贡献,其实就是\((a_i-b_i)^2\),这一点比较秒,然后就是随便卷一卷了

\[ H(x)=\sum_{i=0}^{m}F_{i+x} G_i \]

\(x\) 即偏移量,为啥一秒能做\(1e6\)的NTT

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define cp complex<double>
#define fir first
#define sec second
#define int ll
using namespace std;

const int maxn=4e6+10,Mod=998244353;

int pw(int x,int p){int res=1,base=x;while(p){if(p&1)res=1LL*res*base%Mod;base=1LL*base*base%Mod;p>>=1;}return res;}
int Inv(int x){return pw(x,Mod-2);}

int W[maxn],Cw[maxn],rev[maxn];
int deg,lg;
void Init(int len){
	deg=1,lg=0;while(deg<len)deg<<=1,++lg;
	W[0]=Cw[0]=1;int Wp=pw(3,(Mod-1)/deg),Cp=pw(Inv(3),(Mod-1)/deg);
	for(int i=1;i<deg;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),W[i]=1LL*W[i-1]*Wp%Mod,Cw[i]=1LL*Cw[i-1]*Cp%Mod;
}
bool op;

struct Poly{	
	vector<int>f;
	int &operator[](const int &i){return f[i];}
	int operator[](const int &i)const{return f[i];}
	int Deg(){return f.size();}
	int Deg()const{return f.size();}
	void Set(int len){f.resize(len);}
	void Adjust(){while(f.size()>1 && f.back()==0)f.pop_back();}
	void Print(){for(auto it : f)cerr<<it<<" ";cerr<<"\n";}
	void NTT(int deg,int w[],int opt){
		Set(deg);for(int i=0;i<deg;++i)if(i<rev[i])swap(f[i],f[rev[i]]);
		for(int t=deg>>1,m=1;m<deg;m<<=1,t>>=1)for(int i=0;i<deg;i+=(m<<1))for(int j=0;j<m;++j)
		{ int x=f[i+j],y=1LL*w[t*j]*f[i+j+m]%Mod;f[i+j]=(x+y)%Mod,f[i+j+m]=(x-y+Mod)%Mod;}
		if(opt==-1 && op==false){int inv=::Inv(deg);for(int i=0;i<deg;++i)f[i]=1LL*f[i]*inv%Mod;}
	}
	friend Poly operator * (const Poly &x,const Poly &y){
		Poly res,A=x,B=y;
		Init(A.Deg()+B.Deg()-1);
		A.NTT(deg,W,1);op=true;B.NTT(deg,Cw,-1);op=false;res.Set(deg);
		for(int i=0;i<deg;++i)res[i]=1LL*A[i]*B[i]%Mod;
		res.NTT(deg,Cw,-1);res.Adjust();
		return res;
	}
	void operator *= (const Poly &x){
		Poly A=x;
		Init(Deg()+A.Deg()-1);
		NTT(deg,W,1),A.NTT(deg,W,1);
		for(int i=0;i<deg;++i)f[i]=1LL*f[i]*A[i]%Mod;
		NTT(deg,Cw,-1);Adjust();
	}
}F,G;
int n,m;
char s[maxn>>1],t[maxn>>1];
int prea[maxn>>1],preb[maxn>>1];

void solve(){ 
	cin>>s>>t;
	int n=strlen(s),m=strlen(t);
	F.Set(n),G.Set(m);
	for(int i=0;i<n;++i)F[i]=(s[i]-'0'),prea[i]=prea[max(i-1,0LL)]+(s[i]-'0');
	for(int i=0;i<m;++i)G[i]=(t[i]-'0'),preb[i]=preb[max(i-1,0LL)]+(t[i]-'0');
	F=F*G;
	int ans=m;
	for(int i=0;i+m-1<n;++i){
		if(i>0)ans=min(ans,(prea[i+m-1]-prea[i-1]+preb[m-1]-2*F[i]+Mod)%Mod);
		else ans=min(ans,(prea[i+m-1]+preb[m-1]-2*F[i]+Mod)%Mod);
	}
	cout<<(ans%Mod+Mod)%Mod<<"\n";
}

#undef int
int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


T4 勇者的后缀

后缀数组的题,一看后缀LCP字典序这必后缀数组啊,管他noip不noip的
根据后缀数组的结论,对于一组询问\(x,l,r\),我们可以找到后缀\(x\)\([l,r]\)内排名的前驱后继,\(x\)与两者的\(LCP\)\(\max\)就是第一问的答案。由于\(high\)数组上取\(\min\)的单调性,能够得到这个长度的\(LCP\)的后缀的排名一段连续的区间,二分找到这个区间的左界,然后找到大于等于左界且小于后缀\(x\)的在区间出现过的最小排名即可,大于\(x\)的显然一定是后继最优。对于查前驱后继和最小,可以用值域主席树,由于是同时区间和值域的,所以我只会暴力查排名再查第\(K\)大,有没有巨佬教教我怎么查前驱后继。

点击查看代码
#include <bits/stdc++.h>
typedef long long ll;typedef unsigned long long ull; typedef double db;typedef long double ldb;
#define fre(x) freopen(#x ".in","r",stdin),freopen(#x ".out","w",stdout)
#define Rep(i,a,b) for(int i=a;i<=b;++i) 
#define Dwn(i,a,b) for(int i=a;i>=b;--i)
#define pii pair<int,int>
#define mair make_pair
#define fir first
#define sec second
using namespace std;

const int maxn=2e5+10,INF=20051107;

int rk[maxn],sec[maxn],sa[maxn],tub[maxn],heg[maxn];
int st[maxn][19],lg[maxn];
int n,M=200,m;
char s[maxn];
int root[maxn];

struct ZXS{
	#define LCH tr[rt].lch
	#define RCH tr[rt].rch
	struct Tree{ int lch,rch,sum; }tr[maxn*40];
	int tot;
	void Pushup(int rt){ tr[rt].sum=tr[LCH].sum+tr[RCH].sum; }
	void Modify(int &rt,int p,int l,int r,int x,int w){
		if(!rt)rt=++tot,tr[rt]=tr[p];
		if(l==r)return tr[rt].sum=w,void();
		int mid=(l+r)>>1;
		if(x<=mid){ LCH=0;Modify(LCH,tr[p].lch,l,mid,x,w); }
		else { RCH=0;Modify(RCH,tr[p].rch,mid+1,r,x,w); }
		Pushup(rt);
	}
	/*int QueryMin(int rt,int p,int l,int r,int s,int t){
		if(t<s)return INF;
		if(!rt)return INF;
		if(tr[rt].sum-tr[p].sum==0)return INF;
		if(l==r)return l;
		int mid=(l+r)>>1;
		int res=INF;
		if(s<=mid && (tr[LCH].sum-tr[tr[p].lch].sum))res=QueryMin(LCH,tr[p].lch,l,mid,s,t);
		if(res!=INF)return res;
		if(t>mid && (tr[RCH].sum-tr[tr[p].rch].sum))return QueryMin(RCH,tr[p].rch,mid+1,r,s,t);
		return INF;
	}
	int QueryMax(int rt,int p,int l,int r,int s,int t){
		if(t<s)return INF;
		if(!rt)return INF;
		if(tr[rt].sum-tr[p].sum==0)return INF;
		if(l==r)return l;
		int mid=(l+r)>>1;
		int res=INF;
		if(t>mid && (tr[RCH].sum-tr[tr[p].rch].sum))return QueryMax(RCH,tr[p].rch,mid+1,r,s,t);
		if(res!=INF)return res;
		if(s<=mid && (tr[LCH].sum-tr[tr[p].lch].sum))return QueryMax(LCH,tr[p].lch,l,mid,s,t);
		return INF;
	}*/
	int Rank(int rt,int p,int l,int r,int x){
		if(!rt)return 0;
		if(tr[rt].sum-tr[p].sum==0)return 0;
		if(l==r)return 0;
		int mid=(l+r)>>1;
		if(x<=mid)return Rank(LCH,tr[p].lch,l,mid,x);
		else return (tr[LCH].sum-tr[tr[p].lch].sum)+Rank(RCH,tr[p].rch,mid+1,r,x);
	}
	int Kth(int rt,int p,int l,int r,int x){
		if(l==r)return l;
		int mid=(l+r)>>1;
		int lsum=(tr[LCH].sum-tr[tr[p].lch].sum);
		if(lsum>=x)return Kth(LCH,tr[p].lch,l,mid,x);
		else return Kth(RCH,tr[p].rch,mid+1,r,x-lsum);
	}
}T;

void SA(){
	Rep(i,1,n)++tub[rk[i]=s[i]],lg[i]=lg[i>>1]+1;
	Rep(i,1,M)tub[i]+=tub[i-1];
	Dwn(i,n,1)sa[tub[rk[i]]--]=i;
	for(int w=1;;w<<=1){
		int p=0;
		Rep(i,n-w+1,n)sec[++p]=i;
		Rep(i,1,n)if(sa[i]>w)sec[++p]=sa[i]-w;
		Rep(i,1,M)tub[i]=0;
		Rep(i,1,n)++tub[rk[i]];
		Rep(i,1,M)tub[i]+=tub[i-1];
		Dwn(i,n,1)sa[tub[rk[sec[i]]]--]=sec[i],sec[i]=0;
		swap(rk,sec);
		rk[sa[1]]=1,p=1;
		Rep(i,2,n)rk[sa[i]]=(sec[sa[i]]==sec[sa[i-1]] && sec[sa[i]+w]==sec[sa[i-1]+w]) ? p : ++p;
		if(p==n)break;
		M=p;
	}int k=0;
	for(int i=1;i<=n;i++){
		if(rk[i]==1)continue;
		if(k)--k;
		while(s[i+k]==s[sa[rk[i]-1]+k])++k;
		heg[rk[i]]=k;
	}
	Rep(i,1,n)st[i][0]=heg[i];
	Rep(j,1,18)Rep(i,1,n-(1<<j)+1)st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
	Rep(i,1,n)T.Modify(root[i],root[i-1],1,n,rk[i],1);
/*	cerr<<"Sort::\n";
	Rep(i,1,n){
		cerr<<sa[i]<<":";
		Rep(j,sa[i],n)cerr<<s[j]<<" ";
		cerr<<"\n";
	}
	cerr<<"Finished\n";
*/
}

int Get(int l,int r){++l;int len=lg[r-l+1]-1;return min(st[l][len],st[r-(1<<len)+1][len]);}

pii Sol(int x,int l,int r){
	pii res=mair(-1,0);
	if(x>=l && x<=r)res=mair(n-x+1,rk[x]);
/*	int cnt=0;
	Rep(i,l,r)if(i!=x){
		pii it=mair(min(rk[x],rk[i]),max(rk[x],rk[i]));
		int len=Get(it.fir,it.sec);
		cnt+=(rk[i]<rk[x]);
		if(len>res.fir)res=mair(len,rk[i]);
		else if(len==res.fir && rk[i]<res.sec)
			res=mair(len,rk[i]);
	}*/
	int kx=T.Rank(root[r],root[l-1],1,n,rk[x]);
//	cerr<<kx<<" "<<cnt<<"\n";
	if(kx>0){
		int a=T.Kth(root[r],root[l-1],1,n,kx);
		int len=Get(a,rk[x]);
		if(len>=res.fir){
			int pl=0,pr=a;
			while(pr-pl>1){ int mid=(pl+pr)>>1; if(Get(mid,rk[x])==len)pr=mid; else pl=mid; }
			a=T.Kth(root[r],root[l-1],1,n,T.Rank(root[r],root[l-1],1,n,pr)+1);
			if(len>res.fir)res=mair(len,a);
			else res.sec=min(res.sec,a);
		}
	}
	int tim=1+(x>=l && x<=r);
	if(kx+tim<=r-l+1){
		int a=T.Kth(root[r],root[l-1],1,n,kx+tim);
		int len=Get(rk[x],a);
		if(len>res.fir)res=mair(len,a);
		else if(len==res.fir)res.sec=min(res.sec,a);
	}
	return res;
}

void solve(){
	fre(T4);
	cin>>(s+1);n=strlen(s+1); SA();
	cin>>m;
	while(m--){
		int x,l,r;pii res;
		cin>>x>>l>>r;
		res=Sol(x,l,r);
		cout<<res.fir<<" "<<sa[res.sec]<<"\n";
	}
}

int main (){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);return solve(),0; }


posted @ 2022-10-03 14:39  Delov  阅读(38)  评论(1编辑  收藏  举报