2022/2/12

2022/2/12

Problem - H - Codeforces

最小割求最大闭权子图

网络流建模一般套路:

  1. 对于条件C,需要选取a,b两个,那么源点s与C连贡献边,C与a,b连inf边。这样能保证a,b能同时选,因为切割a边或b边,割的大小都是inf,不是最小割。
  2. 对于条件C,a,b,中只选1个,转换为a,b,连线。

建模方法参考代码。

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<long long , long long >
#define si size()
#define fi first
#define se second
#define pb push_back
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const ll mod=1e9+7;
const ll inf=0x3f3f3f3f;
const int qs=1e6+7;


ll fw[207],fv[207];

ll s,t,head[qs],to[qs],nxt[qs],dis[qs],p;

ll ans=0,n;
vector<int> v[207];

void add(int fx,int tx,ll dx){
	to[p]=tx; dis[p]=dx; nxt[p]=head[fx]; head[fx]=p++;
    //反向边 
	to[p]=fx; dis[p]=0; nxt[p]=head[tx]; head[tx]=p++;
}

//Dinic
ll level[qs],cur[qs];
//level是各点到终点的深度,cur为当前弧优化的增广起点 
bool bfs(){//分层图 
	memset(level,-1,sizeof(level));
	level[s]=0;
	memcpy(cur,head,sizeof(head));
	cur[s]=head[s];
	queue<int> Q;
	Q.push(s);
	while(Q.si){
		int k=Q.front();
		Q.pop();
		for(int i=head[k];i!=-1;i=nxt[i]){
			if(dis[i]>0&&level[to[i]]==-1){
				level[to[i]]=level[k]+1;
				Q.push(to[i]);
				if(to[i]==t) return true;
			}
		}
	}
	return false;
}
ll dfs(int u,ll flow){
	if(u==t) return flow;
	
	ll ret=flow; //剩余的流量
	for(int i=cur[u];i!=-1&&ret>0;i=nxt[i]){
		cur[u]=i;// 当前弧优化
		//如果还能流下去 并且 更深 
		if(dis[i]>0&&level[to[i]]==level[u]+1){
			ll c=dfs(to[i],min(dis[i],ret));
			if(!c) level[to[i]]=-1; //剪枝,出去增广完毕的点 
			ret-=c; //剩余的水流被用了c
			dis[i]-=c;	//减权重 
			dis[i^1]+=c; //反向边加权重 
		}
	} 
	return flow-ret;//返回用掉的水流 
}
//END


void fdfs(int x,int fa,int root,int len){
	add((root-1)*n+len,x+n*n,inf);
	for(int i=0;i<v[x].si;++i){
		int fp=v[x][i];
		if(fp==fa) continue;
		fdfs(fp,x,root,len+1);
	}
}

void build_map(){
	memset(head,-1,sizeof(head));
	s=0,t=n*n+n+1;
	for(int i=1;i<=n;++i) {
		fw[i]=read();
		add(n*n+i,t,fw[i]);	
		// 将负边权连向汇点t,即n个点 
	}
	for(int i=1;i<=n;++i) {
		fv[i]=read();	
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			ans+=fv[j]-fv[j-1];
			//将第i个点周围长度为j的点与源点s建边 
			add(s,(i-1)*n+j,fv[j]-fv[j-1]);
			//将长度为j的与j-1连一条边,流量为inf,表示选长度为j的时候,长度小于j的必选 
			if(j>1) add((i-1)*n+j,(i-1)*n+j-1,inf);
		}
	}
	ll x,y;
	for(int i=1;i<n;++i){
		x=read(),y=read();
		v[x].pb(y),v[y].pb(x);
	} 
	//将点i周围长度为len的点与条件建边 
	for(int i=1;i<=n;++i) fdfs(i,0,i,1);
} 


void solve(){
	while(bfs()){
		ans-=dfs(s,inf);
	}
	cout<<ans<<"\n";
}

int main(){
	n=read();
	build_map();
	solve();
	
}

B-送分了QAQ_数位dp例题 (nowcoder.com)

数位dp模板题

参考代码

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<long long , long long >
#define si size()
#define fi first
#define se second
#define pb push_back
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const ll mod=1e9+7;
const ll inf=0x3f3f3f3f;
const int qs=1e6+7;


ll dp[13][2],bit[13],len;

ll dfs(int pos,int pre,int sta,int lim){
	if(pos==0) return 1;
	if(!lim && dp[pos][sta]) return dp[pos][sta];
	ll ans=0;
	int up=lim ? bit[pos] : 9;
	for(int i=0;i<=up;++i){
		if(pre==3&&i==8) continue;
		if(i==4) continue;
		ans+=dfs(pos-1,i,i==3,lim&&i==up);
	}
	if(!lim) dp[pos][sta]=ans;
	return ans;
}

ll solve(ll x){
	if(x<0) return 0;
	len=0;
	while(x){
		bit[++len]=x%10;
		x/=10;
	}
	return dfs(len,0,0,1);
}
ll n,m;
int main(){
	while(cin>>n>>m){
		if(n==0&&m==0) break;
		ll ans=m-n+1-solve(m)+solve(n-1);
		cout<<ans<<"\n";
	}
}


/*

*/


Problem - D - Codeforces

式子化简后得到:

\((a_1+a_2+...+a_n)^2*(b_1+b_2+...+b_n)^2+(n-2)*(a_1^2+a_2^2+...a_n^2+b_1^2+b_2^2+...+b_n^2)\)

后半部分的值是不变的

那么我们只需要是两个数组的和的乘积最小

用dp记录前i个能组成的数是多少

参考代码

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<long long , long long >
#define si size()
#define fi first
#define se second
#define pb push_back
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const ll mod=1e9+7;
const ll inf=0x3f3f3f3f;
const int qs=1e6+7;

ll T,n,f[2][qs],a[qs],b[qs];
int main(){
	T=read();
	while(T--){
		n=read();
		ll sum=0,s2=0;
		for(int i=1;i<=n;++i) {
			a[i]=read(),sum+=a[i],s2+=a[i]*a[i];	
		}
		for(int i=1;i<=n;++i) {
			b[i]=read(),sum+=b[i],s2+=b[i]*b[i];	
		}
		if(n==1){
			cout<<"0\n";
			continue;
		}
		for(int i=0;i<=sum;++i) f[0][i]=f[1][i]=0;
		f[0][0]=1;
		for(int i=1;i<=n;++i){
			for(int j=0;j<=sum;++j){
				if(f[0][j])
				f[1][j+a[i]]=f[1][j+b[i]]=1;
			}
			for(int j=0;j<=sum;++j) f[0][j]=f[1][j],f[1][j]=0;
		}
		ll ans=inf;
		for(int i=0;i<=sum;++i) {
			if(f[0][i]) ans=min(ans,i*i+(sum-i)*(sum-i));
		}
		ans+=s2*(n-2);
		cout<<ans<<"\n";
	}
	
	
	
}


/*

*/


posted @ 2022-02-13 13:16  Suki_Sugar  阅读(21)  评论(0编辑  收藏  举报
Live2D