Contest 2050 and Codeforces Round #718 (Div. 1 + Div. 2)

A - Sum of 2050

首先n需要满足被2050整除,然后就一定有解。

这是n可以被看成

2050 * x * 10^a + 2050 * y * 10^b  + ... + 2050 * z * 10 ^c

这时候把n/2050就得到了很多个10的幂次相乘,然后我们只需要去看一下有多少个幂次就好了。尽量取大一点就好了

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<stack>
#include<vector>
#include<queue>
#include<unordered_map>
#include<stdio.h>
using namespace std;
const int MAXN = 3e5 + 7;
typedef long long ll;
#define INFll 9223372036854775807
#define INF 0x3f3f3f3f
#define dbg(x) cout << #x << " = " << x << endl;
#define lowbit(n) (n&-n)
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
const ll mod = 1e9 + 7;
ll t, n;
int main(int argc, char const *argv[])
{
	IOS
	cin >> t;
	while(t--)
	{
		cin >> n;
		if (n % 2050)//判断是否满足
		{
			cout << -1 << endl;
			continue;
		}
		ll ans = 0;
		n /= 2050;
		while(n)
		{
			ll k = 1;
			while(k * 10<= n)
				k *= 10;
			n -= k;
			ans++;
		}
		cout << ans << endl;

	}
	return 0;
}

B - Morning Jogging(优先队列模拟一下)

就是对于个节点上的边,最小的边都让现在手上拿的边长最小值最大的人先选即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<stack>
#include<vector>
#include<queue>
#include<unordered_map>
#include<stdio.h>
using namespace std;
const int MAXN = 3e5 + 7;
typedef long long ll;
#define INFll 9223372036854775807
#define INF 0x3f3f3f3f
#define dbg(x) cout << #x << " = " << x << endl;
#define lowbit(n) (n&-n)
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
const ll mod = 1e9 + 7;
ll t, n, m;
vector<int>vec[105];
int mi[105];
struct node
{
	int x;
	friend operator <(node n1, node n2)
	{
		return mi[n1.x] < mi[n2.x];
	}
};
int b[105];
int main(int argc, char const *argv[])
{
	IOS
	cin >> t;
	while(t--)
	{
		cin >> n >> m;
		priority_queue<node>Q;
		memset(mi, INF, sizeof(mi));//存每个人手上拿所有路中的最小值
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				ll x;
				cin >> x;
				vec[i].push_back(x);//存边排序
			}
			sort(vec[i].begin(), vec[i].end());
		}
		for (int i = 0; i < n; i++)
		{
			for (int i = 1; i <= m; i++)
				Q.push(node{i});
			
			for (int j = 0; j < m; j++)
			{
				int x = Q.top().x;//手上边大的人优先选
				Q.pop();//选过就踢掉
				b[x] = vec[i][j];//更新答案
				mi[x] = min(mi[x], vec[i][j]);//更新最小值
			}
			for (int j = 1; j <= m; j++)
				cout << b[j] << " ";
			cout << endl;
		}
	}
	return 0;
}

C - Fillomino 2

题意:给定一个矩阵的主对角线的元素,问能否让每个主对角线上位置延伸出对应该值长度的连续路径。有就输出这个表,没有就-1

很明显,只需要从主对角线开始一层一层往下遍历就行了,对于每个斜线,很明显,对于主对角线来说,如果最上面的值不是1, 那么它只能往下延伸一个位置,然后主对角线上第二个数如果不为1, 那么也只能往下延伸,如果为1,则无法再延伸,这时候主对角线下面的数都只能往左边遍历,然后每个数都延伸出了一位,这时候轮到2不能再延伸了,就这样发现,其实结果以及固定了,只需要再模拟的过程中判断一下有没有冲突就可以了

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<stack>
#include<vector>
#include<queue>
#include<unordered_map>
#include<stdio.h>
using namespace std;
const int MAXN = 3e5 + 7;
typedef long long ll;
#define INFll 9223372036854775807
#define INF 0x3f3f3f3f
#define dbg(x) cout << #x << " = " << x << endl;
#define lowbit(n) (n&-n)
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
const ll mod = 1e9 + 7;
ll t, n, m;
int a[505][505];
int b[105];
int main(int argc, char const *argv[])
{
	IOS
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i][i];
	int num = 1;//延伸了几层,初始一层
	int judge = 1;//判断有没有冲突
	for (int i = 2; i <= n && judge; i++)
	{
		int flag = 0;//1表示向左,0表示向下
		for (int j = i; j <= n; j++)
		{
			if (a[j - 1][j - i + 1] - num == 0)//遇到被遍历完的数了,那么改变方向
			{
				flag = 1;
			}
			if (a[j][j - i + 1])//冲突
				judge = 0;
			if (flag == 0)
			{
				a[j][j - i + 1] = a[j - 1][j - i + 1];
			}
			else{
				a[j][j - i + 1] = a[j][j - i + 2];
			}
		}
		num++;
	}
	if (judge == 0)
		cout << -1 << endl;
	else
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= i; j++)
			{
				cout << a[i][j] << " ";
			}
			cout << endl;
		}
	}
	
	return 0;
}

D - Explorer Space(滚动数组+dp)

不知道不用滚动会不会爆空间,我也没试过,保险起见上了个滚动


题意:就是对于每个点,都和他上下左右四个方向的相邻点之间有一条双向边,每条边都有一个权值。每个点都可以访问上下左右四个方向的相邻点,并获得这条边的权值,问,正好走往k步后,获得的最小权值总和是多少。
思路:用step来存下每个点往上下左右四个方向之间边的权值。
然后, dp[2][k][i][j]表示该点走了k步获得的最小权值和
很明显,k为奇数的时候不可能
行走k步的状态为,每个点的状态转移方程其实就相当于往四个方向走并且回来,并且加上四个方向k-2的状态取最小,也就是说,假定往上走并回来,那么将会消耗2步,那么其他三个方向也是一样的,因为k-2的状态已经得到了,所以只需要求四个方向的最小值就好了,这样子不断转移就可以了。
for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j < m; j++)
		{
			cin >> step[i][j][4];//1 2 3 4上下左右
			step[i][j + 1][3] = step[i][j][4];
		}
	}
	for (int i = 1; i < n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> step[i][j][2];
			step[i + 1][j][1] = step[i][j][2];
		}
	}
for (int len = 2; len <= k; len += 2)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				dp[num&1][len][i][j] = min(min(dp[(num + 1) & 1][len - 2][i + 1][j] + step[i][j][2] + step[i + 1][j][1], dp[(num + 1) & 1][len - 2][i - 1][j] + step[i][j][1] + step[i - 1][j][2]),min(dp[(num + 1) & 1][len - 2][i][j + 1] + step[i][j][4] + step[i][j + 1][3] , dp[(num + 1) & 1][len - 2][i][j - 1]+ step[i][j - 1][4] + step[i][j][3]));
			}
		}
		num++;
	}

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<stack>
#include<vector>
#include<queue>
#include<unordered_map>
#include<stdio.h>
using namespace std;
const int MAXN = 3e5 + 7;
typedef long long ll;
#define INFll 9223372036854775807
#define INF 0x3f3f3f3f
#define dbg(x) cout << #x << " = " << x << endl;
#define lowbit(n) (n&-n)
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
const ll mod = 1e9 + 7;
ll t, n, k;
int dp[2][25][505][505];
int step[505][505][5];
int main(int argc, char const *argv[])
{
	IOS
	int m;
	cin >> n >> m >> k;
	memset(step, INF, sizeof(step));
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j < m; j++)//左右
		{
			cin >> step[i][j][4];//1 2 3 4上下左右
			step[i][j + 1][3] = step[i][j][4];
		}
	}
	for (int i = 1; i < n; i++)
	{
		for (int j = 1; j <= m; j++)//上下
		{
			cin >> step[i][j][2];
			step[i + 1][j][1] = step[i][j][2];
		}
	}

	if (k % 2)//为奇数
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				cout << -1 << " ";
			}
			cout << endl;
		}
		return 0;
	}
	int num = 0;
	for (int len = 2; len <= k; len += 2)//每次+2,因为要刚好回来
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				dp[num&1][len][i][j] = min(min(dp[(num + 1) & 1][len - 2][i + 1][j] + step[i][j][2] + step[i + 1][j][1], dp[(num + 1) & 1][len - 2][i - 1][j] + step[i][j][1] + step[i - 1][j][2]),min(dp[(num + 1) & 1][len - 2][i][j + 1] + step[i][j][4] + step[i][j + 1][3] , dp[(num + 1) & 1][len - 2][i][j - 1]+ step[i][j - 1][4] + step[i][j][3]));
			}
		}
		num++;
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
			cout << dp[(num + 1)&1][k][i][j] << " ";
		cout << endl;
	}
	return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值