• BZOJ4180 字符串计数 和 SCOI2015 小凸玩矩阵


    字符串计数

    SD有一名神犇叫做Oxer,他觉得字符串的题目都太水了,于是便出了一道题来虐蒟蒻yts1999。

    他给出了一个字符串T,字符串T中有且仅有4种字符 'A', 'B', 'C', 'D'。现在他要求蒟蒻yts1999构造一个新的字符串S,构造的方法是:进行多次操作,每一次操作选择T的一个子串,将其加入S的末尾。

    对于一个可构造出的字符串S,可能有多种构造方案,Oxer定义构造字符串S所需的操作次数为所有构造方案中操作次数的最小值。

    Oxer想知道对于给定的正整数N和字符串T,他所能构造出的所有长度为N的字符串S中,构造所需的操作次数最大的字符串的操作次数。

    蒟蒻yts1999当然不会做了,于是向你求助。

    对于100%的数据,1 ≤ N ≤ 1018,1 ≤ |T| ≤ 105

    题解

    http://jklover.hs-blog.cf/2020/05/27/bzoj-4180-字符串计数/#more

    SAM + 矩阵快速幂 floyd.

    考虑如果给出了串 (S) ,如何算最小操作次数,将 (S) 放到 (T) 的 SAM 上去匹配,若没有出边则返回 (1) ,且操作次数 (+1) .

    可以二分答案 (mid) ,尝试检查用 (mid) 次操作能构造出的串最小长度,若 (le n) ,说明答案 (ge mid) .

    考虑如何求出用 (mid) 次操作能构造的串的最小长度,其实转移只会出现在根节点的出边指向的点中.

    bfs 预处理出它们之间的距离,即要加入多少个字符,对转移矩阵求 (mid​) 次幂即可得到用 (mid​) 次操作的最短距离.

    时间复杂度 (O(|sum|cdot |T|+|sum|^3log^2 n)) ,其中 (|sum|) 代表字符集大小.

    CO int N=2e5+10;
    CO int64 inf=2e18;
    char str[N];
    int last=1,tot=1;
    int ch[N][4],fa[N],len[N];
    
    void extend(int c){
    	int x=last,cur=last=++tot;
    	len[cur]=len[x]+1;
    	for(;x and !ch[x][c];x=fa[x]) ch[x][c]=cur;
    	if(!x) {fa[cur]=1; return;}
    	int y=ch[x][c];
    	if(len[y]==len[x]+1) {fa[cur]=y; return;}
    	int clone=++tot;
    	copy(ch[y],ch[y]+4,ch[clone]);
    	fa[clone]=fa[y],len[clone]=len[x]+1;
    	fa[cur]=fa[y]=clone;
    	for(;ch[x][c]==y;x=fa[x]) ch[x][c]=clone;
    }
    
    struct matrix {int64 v[4][4];};
    
    matrix operator*(CO matrix&a,CO matrix&b){
    	matrix ans;
    	for(int i=0;i<4;++i) fill(ans.v[i],ans.v[i]+4,inf);
    	for(int k=0;k<4;++k)
    		for(int i=0;i<4;++i)for(int j=0;j<4;++j)
    			ans.v[i][j]=min(ans.v[i][j],a.v[i][k]+b.v[k][j]);
    	return ans;
    }
    
    matrix pow(matrix a,int64 b){
    	matrix ans;
    	for(int i=0;i<4;++i) fill(ans.v[i],ans.v[i]+4,0);
    	for(;b;b>>=1,a=a*a)
    		if(b&1) ans=ans*a;
    	return ans;
    }
    
    matrix A;
    int64 dis[N];
    int vis[N];
    
    void bfs(int id,int st){
    	for(int i=1;i<=tot;++i) dis[i]=inf,vis[i]=0;
    	dis[st]=0,vis[st]=1;
    	deque<int> que(1,st);
    	while(que.size()){
    		int x=que.front();que.pop_front();
    		for(int c=0;c<4;++c)if(!vis[ch[x][c]]){
    			if(!ch[x][c]) A.v[id][c]=min(A.v[id][c],dis[x]+1);
    			else{
    				dis[ch[x][c]]=dis[x]+1,vis[ch[x][c]]=1;
    				que.push_back(ch[x][c]);
    			}
    		}
    	}
    }
    
    int64 solve(int64 k){
    	matrix B=pow(A,k);
    	int64 ans=inf;
    	for(int i=0;i<4;++i) ans=min(ans,*min_element(B.v[i],B.v[i]+4));
    	return ans;
    }
    
    int main(){
    	int64 len=read<int64>();
    	scanf("%s",str+1);
    	int n=strlen(str+1);
    	for(int i=1;i<=n;++i) extend(str[i]-'A');
    	for(int i=0;i<4;++i) fill(A.v[i],A.v[i]+4,inf);
    	for(int c=0;c<4;++c) bfs(c,ch[1][c]);
    	int64 L=1,R=len,ans;
    	while(L<=R){
    		int64 mid=(L+R)>>1;
    		if(solve(mid)<=len) ans=mid,L=mid+1;
    		else R=mid-1;
    	}
    	if(solve(ans)<len) ++ans;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    小凸玩矩阵

    小凸和小方是好朋友,小方给小凸一个 (N imes M)(N leq M))的矩阵 (A),要求小凸从其中选出 (N) 个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的 (N) 个数中第 (K) 大的数字的最小值是多少。

    (1 leq K leq N leq M leq 250, 1 leq A_{i, j} leq 10 ^ 9)

    题解

    首先行列连边变成二分图。

    二分答案,看看保留(leq ext{mid})的边能不能凑齐(n-k+1)个即可。

    时间复杂度(O(nmsqrt{n+m}log a))

    CO int N=510,inf=1e9;
    namespace Flow{
    	int S,T;
    	struct edge {int y,c,a;};
    	vector<edge> to[N];
    	int dis[N];
    	
    	IN void init(int n){
    		S=n-1,T=n;
    		for(int i=1;i<=n;++i) to[i].clear();
    	}
    	IN void link(int x,int y,int c){
    		to[x].push_back({y,c}),to[y].push_back({x,0});
    		to[x].back().a=to[y].size()-1,to[y].back().a=to[x].size()-1;
    	}
    	bool bfs(){
    		fill(dis+1,dis+T+1,inf),dis[S]=0;
    		deque<int> que={S};
    		while(que.size()){
    			int x=que.front();que.pop_front();
    			for(CO edge&e:to[x])if(e.c and dis[e.y]==inf)
    				dis[e.y]=dis[x]+1,que.push_back(e.y);
    		}
    		return dis[T]<inf;
    	}
    	int dfs(int x,int lim){
    		if(x==T) return lim;
    		int rest=lim;
    		for(edge&e:to[x])if(e.c and dis[e.y]==dis[x]+1){
    			int delta=dfs(e.y,min(rest,e.c));
    			if(delta==0) {dis[e.y]=inf; continue;}
    			rest-=delta,e.c-=delta,to[e.y][e.a].c+=delta;
    			if(rest==0) break;
    		}
    		return lim-rest;
    	}
    	int main(){
    		int ans=0;
    		while(bfs()) ans+=dfs(S,inf);
    		return ans;
    	}
    }
    
    int a[N][N];
    
    int main(){
    	int n=read<int>(),m=read<int>(),K=n-read<int>()+1;
    	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) read(a[i][j]);
    	function<bool(int)> check=[&](int lim)->bool{
    		Flow::init(n+m+2);
    		for(int i=1;i<=n;++i) Flow::link(Flow::S,i,1);
    		for(int i=1;i<=m;++i) Flow::link(i+n,Flow::T,1);
    		for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
    			if(a[i][j]<=lim) Flow::link(i,j+n,1);
    		return Flow::main()>=K;
    	};
    	int l=1,r=inf;
    	while(l<r){
    		int mid=(l+r)>>1;
    		check(mid)?r=mid:l=mid+1;
    	}
    	printf("%d
    ",l);
    	return 0;
    }
    
  • 相关阅读:
    ajax 异步问题
    mysql update 报 You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode
    JSON string 和 object 转换
    Mybatis insert 返回主键
    switch case 的值
    $(this).attr("checked") 用jquery取checkbox的值 返回undefined
    7天入门JavaScript,第五天
    7天入门JavaScript,第四天
    7天入门JavaScript,第三天
    保持按钮的高亮状态
  • 原文地址:https://www.cnblogs.com/autoint/p/13040361.html
Copyright © 2020-2023  润新知