[CLYZ2017]day17

三元组

image

solution

60分

\(s[i]\)表示以\(i\)结尾的回文串的首项下标和.
\(t[i]\)表示以\(i\)开头的回文串的末项下标和.
答案为\(sum_{i=1}^{|S|-1}s[i]\times{t[i+1]}\).
\(manacher\)求出以每个点为中心的最长回文串半径,此回文串范围内对\(s[\;],t[\;]\)区间覆盖等差数列.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 2000005
#define M 1000000007
using namespace std;
int r[N<<1],s[N],t[N],n,ti,ans;
char a[N<<1];
inline void add_s(int l,int r,int m){
	for(int i=l;i<=r;++i)
		s[i]+=m-i;
}
inline void add_t(int l,int r,int m){
	for(int i=l;i<=r;++i)
		t[i]+=m-i;
}
inline void manacher(){
	int mx=0,id=0;
	m=n=strlen(a+1);
	for(int i=n;i;--i){
		a[i<<1]=a[i];a[i<<1|1]='#';
	}
	n=n<<1|1;
	a[0]='$';a[1]='#';
	for(int i=1;i<=n;++i){
		r[i]=i<mx?min(r[(id<<1)-i],mx-i):1;
		while(a[i+r[i]]==a[i-r[i]]) ++r[i];
		if(i+r[i]>mx) mx=i+r[i],id=i;
		add_s(i+1>>1,(i>>1)+(r[i]-1>>1),i);
		add_t((i+1>>1)-(r[i]-1>>1),i>>1,i); 
	}
}
inline void Aireen(){
	scanf("%d",&ti);
	while(ti--){
		scanf("%s",a+1);
		n=strlen(a+1);
		memset(s,0,sizeof(s));
		memset(t,0,sizeof(t));
		manacher();
		ans=0ll;
		for(int i=2;i<=n;++i){
			ans+=1ll*s[i-1]*t[i]%M;
			if(ans>M) ans-=M;
		}
		printf("%d\n",ans);
	}
}

int main(){
	freopen("triple.in","r",stdin);
	freopen("triple.out","w",stdout);
	Aireen();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

100分

利用差分的思想\(O(1)\)覆盖等差数列,统计的时候计算前缀和即可.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 1000005
#define M 1000000007
using namespace std;
int r[N<<1],s[N],t[N],ks[N],kt[N],n,m,ti,ans;
char a[N<<1];
inline void add_s(int l,int r,int m){
	if(l>r) return;
	s[l]+=m-l;s[r+1]-=m-r;
	if(s[l]>M) s[l]-=M;
	if(s[r+1]<-M) s[r+1]+=M; 
	--ks[l+1];++ks[r+1];
}
inline void add_t(int l,int r,int m){
	if(l>r) return;
	t[l]+=m-l;t[r+1]-=m-r;
	if(t[l]>M) t[l]-=M;
	if(t[r+1]<-M) t[r+1]+=M; 
	--kt[l+1];++kt[r+1];
}
inline void manacher(){
	int mx=0,id=0;
	m=n=strlen(a+1);
	for(int i=n;i;--i){
		a[i<<1]=a[i];a[i<<1|1]='#';
	}
	n=n<<1|1;
	a[0]='$';a[1]='#';
	for(int i=1;i<=n;++i){
		r[i]=i<mx?min(r[(id<<1)-i],mx-i):1;
		while(a[i+r[i]]==a[i-r[i]]) ++r[i];
		if(i+r[i]>mx) mx=i+r[i],id=i;
		add_s(i+1>>1,(i>>1)+(r[i]-1>>1),i);
		add_t((i+1>>1)-(r[i]-1>>1),i>>1,i); 
	}
}
inline void Aireen(){
	scanf("%d",&ti);
	while(ti--){
		scanf("%s",a+1);
		memset(s,0,sizeof(s));
		memset(t,0,sizeof(t));
		memset(ks,0,sizeof(ks));
		memset(kt,0,sizeof(kt));
		manacher();ans=0ll;
		for(int i=1,k1=0,k2=0;i<=m;++i){
			k1+=ks[i];
			s[i]+=s[i-1]+k1;
			if(s[i]>M) s[i]-=M;
			k2+=kt[i];
			t[i]+=t[i-1]+k2;
			if(t[i]>M) t[i]-=M;
		}
		for(int i=2;i<=m;++i){
			ans+=1ll*s[i-1]*t[i]%M;
			if(ans>M) ans-=M;
		}
		printf("%d\n",ans);
	}
}
int main(){
	freopen("triple.in","r",stdin);
	freopen("triple.out","w",stdout);
	Aireen();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

最优价值

image

solution

最大权闭合子图

对于边\((u,v)\),如果选择\(u\),必须选择\(v\).

建图

对于原图中的边\((u,v)\),连边\((u,v)=+\infty\).
如果点\(u\)\(w\)为正,连边\((s,u)=w\);否则连边\((u,t)=-w\).
\(w_{max}=\sum_{w_i>0}{w_i}-Mincut\)

100分

分为三类点:\((i,j)=w(i,j),i=-a,x=-b_x+a_x\).
\((i,j)\)连向\(i,j;i\)连向\(s[i]\).
用最大权闭合子图做即可.

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define K 110
#define N 100000
#define M 1000000
#define INF 1000000000
#define min(a,b) (a<b?a:b)
using namespace std;
struct graph{
	int nxt,to,f;
}e[M];
int w[K][K],p[K][K],c[K],a[10],b[10],g[N],dep[N],n,m,k,s,t,cnt,sum;
char ch[K];
queue<int> q;
inline void addedge(int x,int y,int f){
	e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
} 
inline void adde(int x,int y,int f){
	addedge(x,y,f);addedge(y,x,0);
}
inline bool bfs(int u){
	memset(dep,0,sizeof(dep));
	dep[u]=1;q.push(u);
	while(!q.empty()){
		u=q.front();q.pop();
		for(int i=g[u];i;i=e[i].nxt)
			if(e[i].f>0&&!dep[e[i].to]){
				dep[e[i].to]=dep[u]+1;q.push(e[i].to);
			}
	}
	return dep[t];
}
inline int dfs(int u,int f){
	if(u==t) return f;
	int ret=0;
	for(int i=g[u],d;i&&f;i=e[i].nxt)
		if(e[i].f>0&&dep[e[i].to]>dep[u]){
			d=dfs(e[i].to,min(f,e[i].f));
			f-=d;ret+=d;e[i].f-=d;e[i^1].f+=d;
		}
	if(!ret) dep[u]=-1;
	return ret;
}
inline int dinic(){
	int ret=0;
	while(bfs(s)) ret+=dfs(s,INF);
	return ret;
}
inline void Aireen(){
	scanf("%d",&m);
	while(m--){
		scanf("%d",&n);
		k=n*(n-1)/2;
		s=k+n+11;t=s+1;
		scanf("%s",ch+1);
		for(int i=1;i<=n;++i)
			c[i]=ch[i]-'0';
		for(int i=0;i<=9;++i)
			scanf("%d%d",&a[i],&b[i]);
		sum=0;
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				scanf("%d",&w[i][j]);
		cnt=0;
		for(int i=1;i<n;++i)
			for(int j=i+1;j<=n;++j)
				p[i][j]=++cnt;
		cnt=1;
		memset(g,0,sizeof(g));
		for(int i=1;i<n;++i)
			for(int j=i+1;j<=n;++j){
				sum+=w[i][j]+w[j][i];
				adde(s,p[i][j],w[i][j]+w[j][i]);
				adde(p[i][j],k+i,INF);adde(p[i][j],k+j,INF);
			}
		for(int i=1;i<=n;++i){
			adde(k+i,k+n+c[i]+1,INF);
			adde(k+i,t,a[c[i]]);
		}
		for(int i=0;i<=9;++i)
			adde(k+n+i+1,t,b[i]-a[i]);
		printf("%d\n",sum-dinic());
	}
}
int main(){
	freopen("value.in","r",stdin);
	freopen("value.out","w",stdout);
	Aireen();
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2021-11-27 17:49  Aireen_Ye  阅读(37)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.