Codeforces Round #554 (Div. 2)

A题:
阅读理解题,注意一下代码实现就好。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n, m;
int a[100005];
int b[100005];
int main()
{
	cin >> n >> m;
	int odd= 0;
	int even= 0;
	up(i, 0, n)
	{
		scanf("%d", &a[i]);
		if (a[i] & 1)odd++;
		else even++;
	}
	int ans = 0;
	up(i, 0, m)
	{
		scanf("%d", &b[i]);
		if (b[i] & 1 && even)
		{
			even--;
			ans++;
		}
		else if (!(b[i] & 1) && odd)

		{
			odd--;
			ans++;
		}
	}
	cout << ans << endl;
	return 0;
}

B题:
贪心加上位操作加上模拟。
从右到左找到第一个0,从这里开始一直做题意给的操作直到符合题意。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int main()
{
	int x;
	cin >>x;
	int t=0;
	int temp = 0;
	dwd(i, 31, 0)
	{
		if (x&(1 << i))
		{
			temp = i;
			break;
		}
	}//找到最大的1的位置
	//cout << ((1 << (temp + 1)) - 1);

	vector<int >v;
	up(i, 0, 40)
	{
		if (i & 1)
		{
			x++;
			t++;
			if (x == ((1 << (temp + 1)) - 1))
				break;
		}
		else
		{
			dwd(i, temp, 0)
			{
				if (!(x&(1 << i)))
				{
					t++;
					v.push_back(i+1);
					x ^= ((1 << (i + 1)) - 1);
					//cout << "x" << x << 'i' << i<<endl;
					break;
				}
			}
			if (x == ((1 << (temp + 1)) - 1))
				break;
		}
	}
	cout << t << endl;;
	up(i, 0, v.size())
	{
		cout << v[i] << " ";
	}
	return 0;
}

C题:
数论,暴力
我们知道结论:gcd(a,b)=gcd(a,b-a)。
因为a%x=b%x=0,(a-b)%x=a%x-b%x=0=a%x=b%x。
其中b-a是固定的,所以对于求lcm(a,b),可以转换成1/gcd(a+k,b-a)* (a+k) *(b+k)
b-a不变,那么gcd要小,就要a+k是b-a的因数,对于每个分解,求min(lcm)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
ll a, b;
ll dist;
ll ans = 0;
ll sum = 1e15;
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a%b);
}
int main()
{
	cin >> a >> b;
	if (a > b)swap(a, b);
	if (b%a == 0) { cout << 0 << endl; return 0; }
	dist = b - a;
	if (dist < a)//a比dist大,直接就是dist的倍数就好了
	{
		cout << (dist - a % dist) % dist << endl;
		return 0;
	}
	else
	{
		for (int i = 1; i*i <= dist; i++)
		{
			if (dist%i == 0)
			{
				ll temp = i - (a%i);
				ll sumtemp  = (a + temp)*(b + temp) / gcd(a + temp, b + temp);
				if (sumtemp == sum)
				{
					if (temp < ans)ans = temp;
				}
				if (sumtemp < sum)
				{
					sum = sumtemp;
					ans = temp;
				}
				temp = dist / i - (a % (dist / i));//另外一个也要尝试
				sumtemp = (a + temp)*(b + temp) / gcd(a + temp, b + temp);
				if (sumtemp == sum)if (temp < ans)ans = temp;
				if (sumtemp < sum)sum = sumtemp, ans = temp;
			}
		}
		cout << ans << endl;
	}
	return 0;
}

D题,树,dp
我们可以通过观察发现,其实当经历到树的某一层时,节点中只要左括号减去右括号相等的节点,接下来的叶子完全一样,所以有相当多的重复状态。
第二,从根往下走,要计算最多有多少个边,相当于计算从根节点往下,一层计算了边,一层没有,这样交替往下走直到走不下去。
因为是合法序列,所以一定是偶数层数,所以取1-2,3-4,5-6,。。。这样往下一定是最大的,相当于贪心一下。
然后我们就需要计算,1-2,3-4,5-6,有多少个边在里面。
记dp [i][j][k],i表示左括号,j表示右括号,这样i+j就能表示层数,其实k要不要无所谓。
我这里记录了一个k,k=1表示这个点我们取了,k=0表示没有取。(因为实际上就是计算偶数层有多少个节点。)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
ll dp[1005][1005][2];
ll mod = 1e9 + 7;
ll dfs(int i, int j, int k)
{
	ll &ans = dp[i][j][k];
	if (ans)return ans;
	if (i < n)
	{
		int temp = k ? 0 : 1;
		ans += dfs(i + 1, j, temp)+temp;
		ans %= mod;
	}
	if (i > j)
	{
		int temp = k ? 0 : 1;
		ans += dfs(i, j + 1, temp)+temp;
		ans %= mod;
	}
	return ans;

}
int main()
{
	cin >> n;
	cout << 1+dfs(1, 0, 1) << endl;
}

E题。欧拉路径。
定义:

欧拉回路:每条边恰好只走一次,并能回到出发点的路径

欧拉路径:经过每一条边一次,但是不要求回到起始点

欧拉回路存在性的判定:

无向图
每个顶点的度数都是偶数,则存在欧拉回路。

有向图
每个节顶点的入度都等于出度,则存在欧拉回路。

欧拉路径存在性的判定:

有向图 : 图连通,当且仅当该图所有顶点数的度数为0,或者一个顶点的度数为1,另一个顶点的度数为-1,其他顶点的度数为0。

无向图:图连通,当且仅当该图所有顶点的度数为偶数,或者除了两个度数为奇数外其余的全是偶数。
对于这道题目,我们可以发现
对于一个二元组,(x,y)。
要么b[i]=x,c[i]=y,要么b[i]=y,c[i]=x。
所以这样,打乱过后的b,c数组,上下对于的两个数字,就是原数组的两个数字。
比如
3 4 5 6
4 5 6 7
那么3,4肯定是相邻两个数(原数组),4,5也是相邻,5 6,6 7 以此类推。
所以我们作图,把3-4连一条无向边,4-5连一条无向边,最后连接完毕,就可以发现,如果这个序列存在,那么从一个顶点出发,能够不重复的走边,遍历所有顶点,那么这个序列就是存在并且合法的。
我们就能想到,一笔画,即欧拉路径。
这里的条件刚好能够对应上欧拉路径。
因为一个数字要么不出现,要么出现就是偶数次的,因为 bi,bi+1,和bi+1,bi+2 ,bi+1出现两次。
所以除了头节点和尾节点,都是偶数的度,刚好和欧拉路径存在定理一样。
故我们建图,跑欧拉路径就好了。
用的是Hierholzer 算法。(需要先离散化一下,要不然数组放不下)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
const int N = 2e5+10;
int n;
multiset<int > to[N];//用multiset方便查找和删除
int a[N], b[N],c[N],d[N], lisan[2*N];
int val[N];
int cnt = 0;
vector<int >vec;
void dfs(int v)
{
	if (val[v] == 0) { vec.push_back(v); return; }
	for (auto i = to[v].begin(); i != to[v].end(); i = to[v].begin())
	{
		int u = *i;
		to[v].erase(i);
		to[u].erase(to[u].find(v));
		val[v]--;
		val[u]--;
		dfs(u);
	}
	vec.push_back(v);
}
int main()
{
	n = read();
	up(i, 0, n - 1)
	{
		a[i] = read();
		lisan[cnt++] = a[i];
	}
	up(i, 0, n - 1)
	{
		b[i] = read();
		lisan[cnt++] = b[i];
	}
	up(i, 0, n - 1)
	{
		if (a[i] > b[i])
		{
			cout << "-1" << endl;
			return 0;
		}
	}
	sort(lisan, lisan +cnt);
	cnt = unique(lisan, lisan + cnt)-lisan;
	up(i, 0, n-1)
	{
		c[i] = lower_bound(lisan, lisan + cnt, a[i]) - lisan;
		d[i] = lower_bound(lisan, lisan + cnt, b[i]) - lisan;
	}
	up(i, 0, n-1)
	{
		to[c[i]].insert(d[i]);
		to[d[i]].insert(c[i]);
		val[c[i]]++;
		val[d[i]]++;
	}
	int temp[N];
	int tcnt=0;
	up(i, 0,cnt)
	{
		if (val[i] % 2)temp[++tcnt] = i;
	//	cout << val[i] << endl;
	}
	if (tcnt != 0 && tcnt != 2) { cout << "-1" << endl; return 0; }
	if (tcnt == 0)dfs(0);
	else dfs(temp[1]);
	if (vec.size() != n) { cout << "-1" << endl; return 0; }
	up(i, 0, vec.size())
	{
		cout << lisan[vec[i]] <<" ";
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值