省选模拟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])[i−t[i]>=j,i−t[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;
}