【训练记录】山东济南齐鲁工业大学ACM集训队第二次入队赛同步赛(场外VP)

https://icpc.qlu.edu.cn/contest/66ed8b746002253a77c10d5e

训练情况

场外 rk#2 AK

赛后反思

A题太菜了,没看出来是01背包DP,往前缀和上面想了,写了个假做法。

B题又不认真看题,忘记了 \(= 0\) 的情况。

C题博弈论乱猜

D题未考虑完全导致一次WA

A题

分两组,两组和相同,观察数据范围我们考虑 01 背包,先求出所有的和。显然,如果和为奇数则无法分组,当为偶数的时候,判断能否取出 \(\frac{sum}{2}\) 即可

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e7 + 3;

int dp[N];

void solve(){
	int n; cin>>n;
	vector<int> a(n + 1);
	int sum = 0;
	dp[0] = 1;
	for(int i = 1;i<=n;i++) cin>>a[i],sum+=a[i];
	if(sum&1){
		cout<<"No"<<endl;
		return;
	}
	for(int i = 1;i<=n;i++){
		for(int j = sum/2;~j;j--){
			if(j-a[i] < 0) continue;
			if(dp[j-a[i]]) dp[j] = dp[j-a[i]];
		}
	}
	if(dp[sum/2]) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
}

signed main(){
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}

B题

找没被区间覆盖的点,考虑差分了再前缀和,坑点:\(0\) 也算。

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e6 + 3;
int a[N];

void solve(){
	int n,m; cin>>n>>m;
	for(int i = 1;i<=m;i++){
		int l,r; cin>>l>>r;
		a[l]++,a[r+1]--;
	}
	for(int i = 1;i<=n;i++) a[i]+=a[i-1];
	int ans = 0;
	for(int i = 0;i<=n;i++) if(!a[i]) ans++;
	cout<<ans<<endl;
}

signed main(){
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}

C题

逆天我不会的博弈论,逆天后手必胜的结论,通过玩 \(n \le 4\) 的样例,大胆猜测后手必胜

我又会了,后手有一个必胜策略,就是跟着先手的人走中心对称的那条边,最后出现一个正方形三条边的情况,直接去占即可

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
    cout<<"Tianmingren"<<endl;
}

signed main(){
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}

D题

考虑什么时候走不到 \(n\),当某一位为零的时候,并且前面的点没有办法跨过这个 \(0\)。维护一个最右的边界,同时遇到 \(0\) 判断即可,如果无法跨过答案就是 No,否则 Yes。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int n; cin>>n;
	vector<int> a(n + 1);
	for(int i = 1;i<=n;i++) cin>>a[i];
	int last = 0;
	for(int i = 1;i<n;i++){
		if(a[i]) last = max(last,i+a[i]-1);
		if(!a[i] && last < i){
			cout<<"No"<<endl;
			return;
		}
	}
	cout<<"Yes"<<endl;
}

signed main(){
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}

E题

快读模板 + %99

#include <bits/stdc++.h>
#define int long long

using namespace std;

inline int read(){
	int s = 0; char c = getchar();
	while(!isdigit(c))  c = getchar();
	while(isdigit(c)){
		s = (s << 1) + (s << 3) + (c ^ 48);
		s%=99;
		c = getchar();
	}
	return s;
}

int ans = 0;

void solve(){
	int x; x = read();
	if(!x) ans++;
}

signed main(){
	int T; cin>>T; while(T--)
	solve();
	cout<<ans<<endl;
	return 0;
}

F题

模拟题,我们发现字母的位置是两倍的 \(i\)\(j\),其他都是 # 号。

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 8007;

char ans[N][N];

void solve(){
	int n,m; cin>>n>>m;
	vector<string> s(n + 1);

	for(int i = 0;i<n;i++) cin>>s[i];
	for(int i = 0;i<n;i++){
		for(int j = 0;j<m;j++){
			if(s[i][j] >= 'A' && s[i][j] <= 'Z') s[i][j]+=32;
			else s[i][j] -= 32;
		}
	}
	for(int i = 0;i<n;i++){
		for(int j = 0;j<m;j++){
			ans[(i+1)*2][(j+1)*2] = s[i][j];
		}
	}
	for(int i = 1;i<=2*n+1;i++){
		for(int j = 1;j<=2*m+1;j++){
			if(!ans[i][j]) ans[i][j] = '#';
		}
	}
	for(int i = 1;i<=n*2+1;i++){
		for(int j = 1;j<=m*2+1;j++){
			cout<<ans[i][j];
		}
		cout<<endl;
	}
}

signed main(){
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}

G题

单调不降,我们可以发现减少前面的较大值比增加后面的较小值要更优,减小前面的最大值会让数列变得更容易单调不降,维护一个当前的最大值(考虑 \(O(nlogn)\) 优先队列),若出现比他还小的替换掉当前最大值更新答案即可

#include <bits/stdc++.h>
#define int long long

using namespace std;

priority_queue<int> q;

int ans;

void solve(){
	int x; cin>>x;
	q.push(x);
	if(x<q.top()){
		ans+=q.top()-x;
		q.pop();
		q.push(x);
	}	
}

signed main(){
	int T; cin>>T; while(T--)
	solve();
	cout<<ans<<endl;
	return 0;
}

H题

天数要向上取整,观察到取模有很好的周期性,把星期都偏移到 \(0 \sim 6\) 上,然后取模即可,然后再加回来

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int x,y,a; cin>>x>>y>>a;
	int add = (x+(y-1))/y;
	a--;
	a+=add;
	a%=7;
	a++;
	cout<<a<<endl;
}

signed main(){
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}
posted @ 2024-10-07 21:31  MNNUACM_2024ZY  阅读(43)  评论(0编辑  收藏  举报