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

比賽鏈接:https://zhixincode.com/contest/17

A 奪寶奇兵

題解:因爲是先從1->n再從n->1,所以我們可以考慮當成一遍走,即每次的選擇無非[aiai+1,bibi+1][aibi+1,biai+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}]。然後取minmin再加上dis(an,bn)dis(a_n,b_n)即可。

#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×43 \times4以上的矩陣,我們可以知道是可以到達任意一個點的。然後我們判斷起點和終點的顏色即可,因爲每次移動點的顏色是黑白交替的。然後小矩陣窩採用的是爆搜,雖然特判一下也可以。

#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;
}

置置置換

題解:考慮第ii個數的排列末尾位置爲jj的方案數。
如果jj爲奇數dp[i][j]=k=1j1dp[i1][k]dp[i][j] = \sum_{k = 1}^{j -1}dp[i - 1][k]
如果jj爲偶數,我們可以考慮將前面比jj大的數都加一,這樣就有dp[i][j]=k=ji1dp[i1][k]dp[i][j] = \sum_{k = j}^{i-1}dp[i -1][k]
這樣做是O(N3)O(N^3),但是我們發現每次都是從i1i-1轉移過來,所以可以前綴和優化一下。

#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 咆咆咆哮

題解:因爲aa至少總體攻擊力增加,而bb是對在場所有單體加成,因次最優方案必定是把所有aa上完,再釋放bb。所以我們可以考慮貪心枚舉aa的個數。但是怎麼貪心呢?假設我們當前選了iibb,那麼我們將其中第jj個卡片換成aa,所獲得的收益是+a[j]b[j]i+a[j] - b[j] \cdot i,因此我們可以以此來排序從而優先選擇收益大的aa

#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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章