CCPC-Wannafly Winter Camp Day4 (Div2, onsite) A C F G I

9 篇文章 0 订阅
8 篇文章 0 订阅

比赛链接:https://zhixincode.com/contest/17

A 夺宝奇兵

题解:因为是先从1->n再从n->1,所以我们可以考虑当成一遍走,即每次的选择无非 [ a i → a i + 1 , b i → b i + 1 ] 或 者 [ a i → b i + 1 , b i → a i + 1 ] [a_i\rightarrow a_{i+1},b_i\rightarrow b_{i+1}]或者[a_i\rightarrow b_{i+1},b_i\rightarrow a_{i+1}] [aiai+1,bibi+1][aibi+1,biai+1]。然后取 m i n min min再加上 d i s ( a n , b n ) dis(a_n,b_n) dis(an,bn)即可。

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 100100;

struct node{
	int x,y;
}a[N],b[N];

int dis(node u,node v)
{
	return abs(u.x - v.x) + abs(u.y - v.y);
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	int n,m;
	cin >> n >> m;
	long long ans = 0;
	for(int i = 1; i <= n; ++i) {
		scanf("%d %d %d %d",&a[i].x,&a[i].y,&b[i].x,&b[i].y);
		if(i == 1) continue;
		ans += min(dis(a[i - 1], a[i]) + dis(b[i - 1], b[i]), dis(a[i - 1], b[i]) + dis(b[i - 1], a[i]));
	}
	cout << ans + dis(a[n],b[n]) << endl;
	return 0;
}

C 最小边覆盖

题解:易发现对于每一条边,两点的度都大于1,那么这条边就是多余的。

#include<bits/stdc++.h>

using namespace std;
const int N = 3E5+10;
int cnt[N], u[N],v[N];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	int n,m;
	cin >> n >> m;
	for(int i = 0; i < m; ++i) {
		scanf("%d %d",&u[i],&v[i]);
		cnt[u[i]]++;
		cnt[v[i]]++;
	}
	for(int i = 0; i < m; ++i) {
		if(cnt[u[i]] > 1 && cnt[v[i]] > 1) {
			return puts("No"),0;
		}
	}
	puts("Yes");
    return 0;
}

F 小小马

题解:对于 3 × 4 3 \times4 3×4以上的矩阵,我们可以知道是可以到达任意一个点的。然后我们判断起点和终点的颜色即可,因为每次移动点的颜色是黑白交替的。然后小矩阵窝采用的是爆搜,虽然特判一下也可以。

#include<bits/stdc++.h>

using namespace std;

int dir[8][2] = {-2,-1, -2,1, -1,-2, -1,2, 1,-2, 1,2, 2,-1, 2,1};
bool vis[11][11];
int n,m,sx,sy,ex,ey,rec;

bool isWhite(int x,int y)
{
	return (x & 1) == (y & 1);
}

void dfs(int x,int y,int white,int black)
{
	if(x == ex && y == ey) {
		if(white == black) {
			rec = 1;
			return;
		}
	}
	for(int i = 0; i < 8; ++i) {
		int tx = x + dir[i][0];
		int ty = y + dir[i][1];
		if(tx < 1 || tx > n || ty > m || ty < 1 || vis[tx][ty])
			continue;
		vis[tx][ty] = 1;
		if(isWhite(tx,ty)) white++;
		else black++;
		dfs(tx,ty,white,black);
	}
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("input.in", "r", stdin);
#endif
	cin >> n >> m >> sx >> sy >> ex >> ey;
	if (n >= 3 && m >= 3) {
		if ((sx == 2 && sy == 2) || (ex == 2 && sy == 2)) {
			puts("No");
			return 0;
		}
		if (isWhite(sx, sy) == isWhite(ex, ey))
			puts("No");
		else
			puts("Yes");
	} else {
		if(n == 2) {
			int k1 = abs(sy - ey);
			if(abs(sx - ex) == 1 && k1 % 2 == 0 && k1 % 4 != 0) {
				puts("Yes");
			}else{
				puts("No");
			}
			return 0;
		}else if(m == 2){
			int k1 = abs(sx - ex);
			if(abs(sy - ey) == 1 && k1 % 2 == 0 && k1 % 4 != 0) {
				puts("Yes");
			}else{
				puts("No");
			}
			return 0;
		}
		int white = 0, black = 0;
		if (isWhite(sx, sy)) white++;
		else black++;
		dfs(sx, sy, white, black);
		puts(rec ? "Yes" : "No");

	}
	return 0;
}

置置置换

题解:考虑第 i i i个数的排列末尾位置为 j j j的方案数。
如果 j j j为奇数 d p [ i ] [ j ] = ∑ k = 1 j − 1 d p [ i − 1 ] [ k ] dp[i][j] = \sum_{k = 1}^{j -1}dp[i - 1][k] dp[i][j]=k=1j1dp[i1][k]
如果 j j j为偶数,我们可以考虑将前面比 j j j大的数都加一,这样就有 d p [ i ] [ j ] = ∑ k = j i − 1 d p [ i − 1 ] [ k ] dp[i][j] = \sum_{k = j}^{i-1}dp[i -1][k] dp[i][j]=k=ji1dp[i1][k]
这样做是 O ( N 3 ) O(N^3) O(N3),但是我们发现每次都是从 i − 1 i-1 i1转移过来,所以可以前缀和优化一下。

#include<bits/stdc++.h>

using namespace std;
const int mod = 1e9+7;
long long dp[1010][1010];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	int n;
	cin >> n;
	dp[1][1] = 1;
	for(int i = 2; i <= n; ++i) {
		for(int j = 1; j <= i; ++j) {
			if(i & 1) {
				dp[i][j] = (dp[i][j - 1] + dp[i - 1][j - 1]) % mod;
			}else{
				dp[i][j] = (dp[i][j - 1] + dp[i - 1][i - 1] - dp[i - 1][j - 1] + mod) % mod;
			}
		}
	}
	cout << dp[n][n] << endl;
    return 0;
}

I 咆咆咆哮

题解:因为 a a a至少总体攻击力增加,而 b b b是对在场所有单体加成,因次最优方案必定是把所有 a a a上完,再释放 b b b。所以我们可以考虑贪心枚举 a a a的个数。但是怎么贪心呢?假设我们当前选了 i i i b b b,那么我们将其中第 j j j个卡片换成 a a a,所获得的收益是 + a [ j ] − b [ j ] ⋅ i +a[j] - b[j] \cdot i +a[j]b[j]i,因此我们可以以此来排序从而优先选择收益大的 a a a

#include<bits/stdc++.h>

using namespace std;
struct node{
	int a,b;
	long long c;
	bool operator < (const node & u) const {
		return c > u.c;
	}
}f[1010];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	int n;
	cin >> n;
	for(int i = 1; i <= n; ++i) {
		cin >> f[i].a >> f[i].b;
	}
	long long ans = 0, sum = 0;
	for(int i = 1; i <= n; ++i) {
		sum = 0;
		for(int j = 1; j <= n; ++j) {
			f[j].c = f[j].a - f[j].b * i;
		}
		sort(f + 1, f + n + 1);
		for(int j = 1; j <= i; ++j) {
			sum += f[j].a;
		}
		for(int j = i + 1; j <= n; ++j) {
			sum += f[j].b * i;
		}
		ans = max(ans, sum);
	}
	cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值