200723-省选模拟4

省选模拟4

T1

题目描述

题目描述

题解

O ( n 2 ) d p O(n^2)dp O(n2)dp方程很好写出来
f [ i ] f[i] f[i]表示当前选到第 i i i个数的最大分数
转移方程为: f [ i ] = m a x ( f [ i ] , f [ j ] + v a l [ i ] ) [ i − t [ i ] > = j , i − t [ j ] > = j ] f[i]=max(f[i],f[j]+val[i])[i-t[i]>=j,i-t[j]>=j] f[i]=max(f[i],f[j]+val[i])[it[i]>=j,it[j]>=j]
考虑怎么优化
考虑第二个条件,因为当 j j j满足该条件时,后面的 i i i都满足
我们用一个 v e c t o r vector vector来存储每个 j j j在哪个位置后,可以贡献
然后在那个位置加入 j j j,树状数组维护第一个条件
O ( n l o g n ) O(nlogn) O(nlogn)

代码
#include<bits/stdc++.h>
#define int long long
#define M 3000009
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int tr[M],b[M],l[M],r[M],tot,f[M],val[M],t[M],n,ans,len,now[M];
vector<int>q[M];
int lowbit(int i){return i&(-i);}
void update(int x,int y){
	//printf("%lld %lld %lld\n",x,y,len);
	while(x<=len+1){
		tr[x]=max(tr[x],y);
		x+=lowbit(x);
	}
}
int solve(int x){
	int sum=0;
	while(x>0){
		sum=max(tr[x],sum);
		x-=lowbit(x);
	}return sum;
}
signed main(){
	//freopen("td.in","r",stdin);
	//freopen("fc.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++) t[i]=read(),r[i]=b[++tot]=t[i]+i,l[i]=b[++tot]=max(0ll,i-t[i]),now[i]=b[++tot]=i;
	for(int i=1;i<=n;i++) val[i]=t[i]*read();
	sort(b+1,b+tot+1);
	len=unique(b+1,b+tot+1)-b-1;
	for(int i=1;i<=n;i++){
		int posl=lower_bound(b+1,b+len+1,l[i])-b;
		int posr=lower_bound(b+1,b+len+1,r[i])-b;
		int posn=lower_bound(b+1,b+len+1,now[i])-b;
		l[i]=posl,r[i]=posr,now[i]=posn;
		//printf("%lld %lld %lld\n",t[i],l[i],r[i]);
	}
	for(int i=1;i<=n;i++){
		f[i]=val[i];
		for(int j=0;j<q[now[i]].size();j++){
			int x=q[now[i]][j];
			update(now[x]+1,f[x]);
		}f[i]=max(f[i],solve(l[i]+1)+val[i]);
		//printf("%lld\n",f[i]);
		ans=max(f[i],ans);
		q[r[i]].push_back(i);
	}printf("%lld\n",ans);
	return 0;
}

T2

题目描述

题目描述

题解

咕咕咕~

代码

T3

题目描述

题目描述

题解

显然答案满足单调性
于是二分答案
然后对每个串,找到它长度小于当前枚举的x的子序列(序列自动机),如果个数大于n,那么就停止寻找,因为这个串一定满足条件,然后将剩下的子序列和串做二分图最大匹配,如果等于当前串的数量,即合法

代码(爆搜找子串)
#include<bits/stdc++.h>
#include<tr1/unordered_map> 
#define ull unsigned long long
#define M 100009
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int point,tot,nxt[M],first[M],to[M],match[M],n,maxn,len[M],cnt1,cnt2,sum;
bool flag,vis[M];
ull has;
const int h=31;
char s[309][309];
tr1::unordered_map<ull,int>mp1,mp2;
vector<int>a[309];
void add(int x,int y){
	nxt[++tot]=first[x];
	first[x]=tot;
	to[tot]=y;
}
void clear(){
	tot=0;mp2.clear();
	memset(match,0,sizeof(match));
	memset(first,0,sizeof(first));
}
void addedge(int num){
	for(int i=0;i<a[num].size();i++)
		add(a[num][i],num);
//	for(int i=0;i<a[num].size();i++)
//	 	printf("%d ",a[num][i]);
//	printf("\n");
}
void dfs(int num,int pos,int lim){//cnt1表示选择了多少字符,cnt2表示有多少符合条件的子串 
//printf("%d\n",cnt2);
	if(flag) return;
	if(cnt2==n){flag=1;return;}
	if(cnt1>=lim||cnt1>=len[num]||pos>len[num]) return; 
	ull has1=has;
	has=has*h+s[num][pos]-'a'+1;cnt1++;
	if(mp2.find(has)==mp2.end()) mp2[has]=++point;
	if(mp1.find(has)==mp1.end()) cnt2++,mp1[has]=1,a[num].push_back(mp2[has]);
	dfs(num,pos+1,lim);
	has=has1;cnt1--;
	if(flag) return;
	dfs(num,pos+1,lim);
}
bool dfs2(int r){
	for(int i=first[r];i;i=nxt[i]){
		int u=to[i];
		if(!vis[u]){
			vis[u]=1;
			if(!match[u]||dfs2(match[u])){
				match[u]=r;
				return 1;
			}
		}
	}return 0;
}
int getans(){
	int ans=0;
	for(int i=n+1;i<=point;i++){
		memset(vis,0,sizeof(vis));
		if(dfs2(i)) ans++;
	}//printf("%d\n",ans);
	return ans;
}
bool check(int x){
	//printf("%d\n",x);
	clear();
	sum=point=n;
	bool bj=1;
	for(int i=1;i<=n;i++){
		a[i].clear();
		mp1.clear();flag=0;
		cnt1=cnt2=0;has=0;
		dfs(i,1,x);
		//printf("%d\n",cnt2);
		if(!flag) addedge(i),bj=0;
		else sum--;
	}return (bj==1)||(getans()==sum);
}
signed main(){
	//freopen("diff.in","r",stdin);
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s[i]+1);
		len[i]=strlen(s[i]+1);
		maxn=max(maxn,len[i]);
	}int l=1,r=maxn+1;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}if(r==maxn+1) printf("-1\n");
	else printf("%d\n",r);
	return 0;
}
代码(dinic算法)
#include<bits/stdc++.h>//序列自动机+dinic 105分 
#include<tr1/unordered_map> 
#define ull unsigned long long
#define M 400009
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int point,tot=1,nxt[M],first[M],to[M],n,maxn,len[M],sum,nxtt[309][26],last[26],w[M],now[M],d[M],ss,t,cnt;
ull has;
const int h=31;
const int inf=1e9+7;
char s[309][309];
tr1::unordered_map<ull,int>mp;
vector<int>a[309];
void add(int x,int y,int z){
	nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
	nxt[++tot]=first[y],first[y]=tot,to[tot]=x,w[tot]=0;
}
bool bfs(){
	memset(d,0,sizeof(d));
	d[ss]=1;queue<int>q;
	q.push(ss);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];
			if(w[i]&&!d[v]){
				d[v]=d[u]+1;
				q.push(v);
				if(v==t) return 1;
			}
		}
	}return 0;
}
int dinic(int x,int flow){
	if(x==t||!flow) return flow;
	int rest=flow,i;
	for(i=now[x];i&&rest;i=nxt[i]){
		int v=to[i];
		if(d[v]==d[x]+1&&w[i]){
			int k=dinic(v,min(w[i],rest));
			w[i]-=k;w[i^1]+=k;rest-=k;
		}
	}now[x]=i;
	return flow-rest;
}

void clear(){
	tot=1;mp.clear();//tot置为1!!!!!!!!(掀桌子) 
	memset(w,0,sizeof(w));
	memset(first,0,sizeof(first));
}
int getans(){
	int ans=0,flow=0,cnt1=0;
	for(int i=1;i<=n;i++){
		if(a[i].size()>=n) sum--;
		else for(int j=0;j<a[i].size();j++) add(i,a[i][j],1);
	}ss=0,t=point+1;
	for(int i=1;i<=n;i++) if(a[i].size()<n) add(ss,i,1),cnt1++;
	for(int i=n+1;i<=point;i++)  add(i,t,1);
	while(bfs()){
		for(int i=0;i<=t;i++) now[i]=first[i];
		if(flow=dinic(ss,inf)) ans+=flow;
	}return ans;
}
void dfs(int num,int u,int lim){
	if(a[num].size()==n) return; 
	if(cnt>=lim) return;
	ull has1=has;cnt++;
	has=has*h+s[num][u]-'0'+1;
	if(mp.find(has)==mp.end()) mp[has]=++point;
	a[num].push_back(mp[has]);
	for(int i=0;i<26;i++)
		if(nxtt[u][i]) dfs(num,nxtt[u][i],lim);
	cnt--;has=has1; 
}
void getson(int num,int lim){
	memset(last,0,sizeof(last));
	memset(nxtt,0,sizeof(nxtt));
	for(int i=len[num];i>=1;i--){
		for(int j=0;j<26;j++)
			nxtt[i][j]=last[j];
		last[s[num][i]-'a']=i;
	}
	for(int i=0;i<26;i++) 
		if(last[i]) cnt=0,dfs(num,last[i],lim);
}

bool check(int x){
	clear();sum=point=n;
	for(int i=1;i<=n;i++) a[i].clear(),getson(i,x);
	return getans()==sum;
}
signed main(){
	//freopen("abbr3_15.in","r",stdin);
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s[i]+1);
		len[i]=strlen(s[i]+1);
		maxn=max(maxn,len[i]);
	}int l=1,r=maxn+1;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}if(r==maxn+1) printf("-1\n");
	else printf("%d\n",r);
	return 0;
}
代码(匈牙利算法)
#include<bits/stdc++.h>//序列自动机加匈牙利 84分 
#include<tr1/unordered_map> 
#define ull unsigned long long
#define M 100009
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int point,tot,nxt[M],first[M],to[M],match[M],n,maxn,len[M],sum,nxtt[309][26],last[26],cnt;
bool flag,vis[M];
ull has;
const int h=31;
char s[309][309];
tr1::unordered_map<ull,int>mp;
vector<int>a[309];
void add(int x,int y){
	nxt[++tot]=first[x];
	first[x]=tot;
	to[tot]=y;
}
void clear(){
	tot=0;
	mp.clear();
	memset(match,0,sizeof(match));
	memset(first,0,sizeof(first));
}
void addedge(int num){
	if(a[num].size()>=n){sum--;return;}
	for(int i=0;i<a[num].size();i++)
		add(a[num][i],num);
//	for(int i=0;i<a[num].size();i++)
//	 	printf("%d ",a[num][i]);
//	printf("\n");
}

bool dfs2(int r){
	for(int i=first[r];i;i=nxt[i]){
		int u=to[i];
		if(!vis[u]){
			vis[u]=1;
			if(!match[u]||dfs2(match[u])){
				match[u]=r;
				return 1;
			}
		}
	}return 0;
}
int getans(){
	int ans=0;
	for(int i=n+1;i<=point;i++){
		memset(vis,0,sizeof(vis));
		if(dfs2(i)) ans++;
	}printf("%d %d\n",ans,sum);
	return ans;
}
void dfs(int num,int u,int lim){
	if(a[num].size()==n) return; 
	if(cnt>=lim) return;
	ull has1=has;cnt++;
	has=has*h+s[num][u]-'0'+1;
	//printf("%d\n",u);
	if(mp.find(has)==mp.end()) mp[has]=++point;
	a[num].push_back(mp[has]);
	for(int i=0;i<26;i++)
		if(nxtt[u][i]) dfs(num,nxtt[u][i],lim);
	cnt--;has=has1; 
}
void getson(int num,int lim){
	memset(last,0,sizeof(last));
	memset(nxtt,0,sizeof(nxtt));
	for(int i=len[num];i>=1;i--){
		for(int j=0;j<26;j++)
			nxtt[i][j]=last[j];
		last[s[num][i]-'a']=i;
	}
	for(int i=0;i<26;i++) 
		if(last[i]) cnt=0,dfs(num,last[i],lim);
}
bool check(int x){
	printf("%d\n",x);
	clear();sum=point=n;
	for(int i=1;i<=n;i++) a[i].clear(),getson(i,x),addedge(i); 
	printf("%d\n",tot);
	return getans()==sum;
}
signed main(){
	freopen("abbr3_15.in","r",stdin);
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s[i]+1);
		len[i]=strlen(s[i]+1);
		maxn=max(maxn,len[i]);
	}int l=1,r=maxn+1;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}if(r==maxn+1) printf("-1\n");
	else printf("%d\n",r);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值