• 10.3CSPS模拟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; }
    
    
    
  • 相关阅读:
    Algs4-1.3.37Josephus问题
    Algs4-1.3.35随机队列
    Algs4-1.3.33一个双向队列Deque的可变长环形数组实现
    Algs4-1.3.34随机背包
    Algs4-1.3.33一个双向队列Deque-双向链表实现
    Algs4-1.3.32链表实现Stack和Queue的合体Steque
    Algs4-1.3.31实现双向链表
    Algs4-1.3.30反转链表
    C语言多级指针
    spring mvc@ModelAttribute与@SessionAttributes的执行流程
  • 原文地址:https://www.cnblogs.com/Delov/p/16750515.html
Copyright © 2020-2023  润新知