2019 ICPC Shanghai Site记录

K-Color Graph

发现 \(n\) 只有 \(16\),可以爆搜!
考虑到无奇环和二分图互为充要条件,只要暴力枚举在二分图左边还是右边,根据定义看最多能保留多少条边就可以了!

查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n,m,maxn,u[100005],v[100005],color[20005];
vector<int>nbr[20005],_nbr[20005];
void add(int u,int v){
	nbr[u].push_back(v);
}
void _add(int u,int v){
	_nbr[u].push_back(v);
}
int vis[20];
int ans;
bool dfs(int cur,int c){
	color[cur]=c;
	for(int i=0;i<_nbr[cur].size();i++){
		int nxt=_nbr[cur][i];
		if(color[nxt]==3-c)continue;
		else if(color[nxt]==c)return 0;
		else if(color[nxt]==0){
			if(dfs(nxt,3-c)==0)return 0;
		}
	}
	return 1;
}
void work(){
	int tot=0;
	for(int i=1;i<=m;++i){
		if(!vis[u[i]]||!vis[v[i]]){
			continue;
		}
		if(vis[u[i]]==vis[v[i]])continue;
		else tot++;
	}
	ans=max(ans,tot);
}
void dfss(int cur){
	if(cur==n+1){
		work();
		return;
	}
	vis[cur]=1;
	dfss(cur+1);
	vis[cur]=2;
	dfss(cur+1);
}
int main(){
	ios::sync_with_stdio(0);
	cin>>t;
	int cntt=0;
	while(t--){
		cin>>n>>m;
		ans=0;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=m;++i){
			cin>>u[i]>>v[i];
		}
		dfss(1);
		cout<<"Case #"<<++cntt<<": "<<ans<<'\n';
	}
	return 0;
}

D-Spanning Tree Removal

一个完全图,一次删一棵树,问你最多能删多少次。
有一个奇怪的思路就是你可以反复横跳删,先删完左边再删右边最近的没删的(
然后过了。
感性理解这是对的(

查看代码
#include<bits/stdc++.h>
using namespace std;
int t;
int n;
bool vis[1005][1005];
int main(){
	ios::sync_with_stdio(0);
	cin>>t;
	int cnt=0;
	while(t--){
		cin>>n;
		cout<<"Case #"<<++cnt<<": "<<n/2<<'\n';
		for(int i=1;i<=n/2;++i){
			int k=i;
			int flg=1;
			for(int j=1;j<n;++j){
				cout<<(k+1)<<' '<<(k+flg*j+n)%n+1<<'\n';
				k=(k+flg*j+n)%n;
				flg*=-1;
			}
		}
	}
	return 0;
}

E-Cave Escape

你发现格子可以重复走,只是不能重复得到贡献。
你又发现你不能闪现瞬移,那么路径一定是联通的!
答案要最大!
那就是,最大生成树!
\(n\times m=10^6\)\(O(n\times m\times \log nm)\) 特别的稳啊(
于是便过了,但是要稍微卡卡常(

其实你也可以使用桶排来避免卡常(
因为 \(p\) 的值比较小。

查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,m,s,xxxx,y;
int _w[1001][1001],x[1000001];
int fa[1000001];
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void unionn(int a,int b){
	xxxx=find(a),y=find(b);
	if(xxxx==y)return;
	fa[xxxx]=y;
	return;
}
struct edge{
	int u,v,w;
}q[2000001];
int calc(int i,int j){
	return (i-1)*m+j;
}
bool cmp(edge a,edge b){
	return a.w>b.w;
}
int i,j;
signed main(){
	int xx=0;
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	int xxx,tot,u,v,a,b,c,p,cnt;
	while(t--){
		cin>>n>>m>>s>>s>>s>>s;
		cin>>x[1]>>x[2]>>a>>b>>c>>p;
		fa[1]=1;fa[2]=2;
		for(i=3;i<=n*m;++i)fa[i]=i,x[i]=(a*x[i-1]+b*x[i-2]+c)%p;
		for(i=1;i<=n;++i)for(j=1;j<=m;++j){
			_w[i][j]=x[calc(i,j)];
		}
		cnt=0;
		for(i=1;i<=n;++i){
			for(j=1;j<=m;++j){
				if(i!=n)q[++cnt]={calc(i,j),calc(i+1,j),_w[i][j]*_w[i+1][j]};
				if(j!=m)q[++cnt]={calc(i,j),calc(i,j+1),_w[i][j]*_w[i][j+1]};
			}
		}
		sort(q+1,q+cnt+1,cmp);
		xxx=0,tot=0;
		for(i=1;i<=cnt;++i){
			u=q[i].u,v=q[i].v;
			if(find(u)==find(v))continue;
			unionn(u,v);
			xxx+=q[i].w;
			++tot;
			if(tot==n*m-1)break;
		}
		cout<<"Case #"<<++xx<<": "<<xxx<<'\n';
	}
	return 0;
} 

H-Tree Partition

显然你可以先二分答案,然后,你用一个动态规划,当答案没有超过二分的 \(lim\) 时就一直从小到大加子树的答案(贪心,让分的段数尽可能小),并且统计一下没有加进去的数量(就是你要断开的边),如果小于 \(k\) 二分出来的这个就是可以的!

查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,k,w[100005],dp[100005];
vector<int>nbr[100005];
int dfs(int cur,int fa,int lim){
	dp[cur]=w[cur];
	vector<int>v;
	int res=0;
	for(auto to:nbr[cur]){
		if(to==fa)continue;
		res+=dfs(to,cur,lim);
		v.push_back(dp[to]);
	}
	sort(v.begin(),v.end());
	int cnt=0;
	for(auto i:v){
		cnt++;
		if(dp[cur]+i<=lim)dp[cur]+=i;
		else{
			res+=v.size()-cnt+1;
			break;
		}
	}
	return res;
}
bool check(int x){
	return dfs(1,0,x)<k;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	int cntt=0;
	while(t--){
		cin>>n>>k;
		for(int i=1;i<=n;++i)nbr[i].clear();
		for(int i=1;i<n;++i){
			int u,v;
			cin>>u>>v;
			nbr[u].push_back(v);
			nbr[v].push_back(u);
		}
		int lt=0,rt=0;
		for(int i=1;i<=n;++i)cin>>w[i],lt=max(lt,w[i]),rt+=w[i];
		lt--;rt++;
		while(lt+1<rt){
			int mid=lt+rt>>1;
			if(check(mid))rt=mid;
			else lt=mid;
		}
		cout<<"Case #"<<++cntt<<": "<<rt<<'\n';
	}
	return 0;
}
posted @ 2023-01-12 15:02  Forever1507  阅读(19)  评论(0编辑  收藏  举报