Codeforces Round #606 Div2

1259E Two Fairs(搜索)

题意:

​ 给一个无向连通图以及图上不同的两点a、b,求出满足条件的不同点对(x,y)个数,其中点x到点y的任意一条路径都会经过a和b两点,(x,y)与(y,x)视作相同( n 2 1 0 5 , n 1 m 5 1 0 5 n\le2*10^5,n-1\le m\le5*10^5 )。

解法:

​ 首先,如果这样的点对存在,a和b必定是图上的两个割点。如果(x,y)满足条件,那么删掉a或者b任意一点后,x与y不再连通。由此,图上的点可以被分为三类:1. 删去点b后,与a连通的点;2. 删去点a后,与b连通的点;3. 同时满足1和2的点。那么设任意第一类点为x,任意第二类点为y,则点对(x,y)满足条件,而其他情况均不满足,因此答案为第一类点个数*第二类点个数。

​ 于是分别以点a和点b为起点开始搜索分别与a和b连通的点,利用set维护,最后遍历1-n计算两类点的数量。

​ 复杂度: O ( n ) O(n)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
vector<int>e[maxn];
set<int>s[2];
int a[2],flag[2][maxn];
void link(int u,int v)
{	e[u].push_back(v),e[v].push_back(u); }
void dfs(int u,int tag)
{
	flag[tag][u]=true;
	if(u==a[tag^1]) return;
	s[tag].insert(u);
	for(int v:e[u])
		if(!flag[tag][v]) dfs(v,tag);
}
int main()
{
	int T,n,m,u,v;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d%d",&n,&m,&a[0],&a[1]);
		for(int i=1;i<=n;i++) e[i].clear();
		s[0].clear(),s[1].clear();
		for(int i=1;i<=m;i++)
			scanf("%d%d",&u,&v),link(u,v);
		dfs(a[0],0),dfs(a[1],1);
		int cnt[2]={0};
		for(int i=1;i<=n;i++) 
			if(i!=a[0]&&i!=a[1]&&(s[0].count(i)^s[1].count(i)))
				cnt[0]+=s[0].count(i),cnt[1]+=s[1].count(i);
		printf("%lld\n",1LL*cnt[0]*cnt[1]);
	}
}

1259F Beautiful Rectangle(构造 数学)

题意:

​ 给n个整数,构造一个 N M N*M 的矩阵使同一行和同一列上无相同数字。最大化 N M N*M 的值 ( n 4 1 0 5 ) (n\le4*10^5)

解法:

​ 设矩阵大小为 N M ( N M ) N*M(N\le M) ,则当矩阵中各数字出现次数的最大值不超过N时,可构造一个矩阵满足同行同列上无相同数字。构造方法如下,从 ( 0 , 0 ) (0,0) 开始填数,当前填到 ( x , y ) (x,y) ,则下一步填 ( ( x + 1 ) % N , ( y + 1 ) % M ) ((x+1)\% N,(y+1)\%M) ;若该处已被填过,则使 x = ( x + 1 ) % N x=(x+1)\%N 。例:当N=4,M=5时,填写次序如下图。

1 17 13 9 5
6 2 18 14 10
11 7 3 19 15
16 12 8 4 20

​ 注意:相同的数字必须被连续的填入矩阵。由于 N M N*M 矩阵中各数字最多出现N次,同行同列上不可能存在相同的数字。

​ 根据以上分析,先利用map预处理出出现次数为 i ( 1 i n ) i(1\le i\le n ) 的数并用vector存放,进而利用前缀和的思想可求出至少出现 i i 的数的个数sum[i]。遍历矩阵行数 i = 1 n i=1\rightarrow\sqrt n ,变量cnt记录在行数为 i i 的矩阵中最多能填多少个数字,于是行数为 i i 的矩阵最大列数 j = c n t / i j=cnt/i ,用 i j i*j 更新答案。确定矩阵大小后按上述方法构造矩阵即可。

​ 复杂度: O ( n l o g n ) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
vector<int>num[maxn];
map<int,int>mp;
int sum[maxn];
int main()
{
	int n,a;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a),mp[a]++;
	for(auto i:mp)
		num[i.second].push_back(i.first);
	sum[n]=num[n].size();
	for(int i=n-1;i;i--)
		sum[i]=sum[i+1]+num[i].size();
	int siz=0,p=0,q=0,cnt=0;
	for(int i=1;i*i<=n;i++)
	{
		cnt+=sum[i];
		int j=cnt/i;
		if(i<=j&&i*j>siz) siz=i*j,p=i,q=j;
	}
	printf("%d\n%d %d\n",siz,p,q);
	vector<vector<int> >ans(p,vector<int>(q));
	int x=0,y=0;
	for(int i=n;i;i--)
		for(int val:num[i])
			for(int j=1;j<=min(i,p);j++)
			{
				if(ans[x][y]) x=(x+1)%p;
				if(!ans[x][y]) ans[x][y]=val;
				x=(x+1)%p,y=(y+1)%q;
			}
	for(int i=0;i<p;i++)
	{
		for(int j=0;j<q;j++)
			printf("%d ",ans[i][j]);
		puts("");
	}
}
发布了5 篇原创文章 · 获赞 3 · 访问量 127

猜你喜欢

转载自blog.csdn.net/weixin_43899905/article/details/103600841