【训练记录】2024年莆田市高中信息学奥赛国庆集训CSP-S提高组(第二天场外)

训练情况

rk#4

\(100 + 100 + 100 + 70 = 370\)

赛后反思

没什么很严重的失误,只是国庆早八起不来,打到后面时间不够做第四题了QAQ,下次一定早起TAT

A题




开场怎么是CF Div4 原题,显然因为 \(a,b,c,d\) 互不相同,最后切出来的结果只有三块或四块,三块的情况是两线没有交叉,四块的情况是两线交叉了,我们考虑从时钟的最外面走一圈,若出现交叉的情况输出 \(4\) 否则输出 \(3\) 即可。

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

using namespace std;

void solve(){
	int a,b,c,d; cin>>a>>b>>c>>d;
	string s;
	for(int i = 1;i<=12;i++){
		if(i == a || i == b) s += "0";
		if(i == c || i == d) s += "1";
	}
	if(s[0] == s[2] && s[1] == s[3]) cout<<4<<endl;
	else cout<<3<<endl;
}

signed main(){
    freopen("time.in","r",stdin);
    freopen("time.out","w",stdout);
	int T; cin>>T; while(T--)
	solve();
	return 0;
}

B题





背包DP缝合题(?)带双重容量+种类01背包,挺板的

DP状态转移方程:

\[dp[pi][li]=max(dp[pi][li],dp[pi-p[i]][li-l[i]]+b[i]) \]

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=1e3+5;

int n,t,w,k[N];
int p[N],l[N],b[N];
int dp[N][N];

void solve(){
	cin>>n>>t>>w;
	for(int i=1;i<=n;i++) cin>>k[i];
	for(int i=1;i<=n;i++) cin>>p[i]>>l[i]>>b[i];
	for(int i=1;i<=n;i++){
		while(k[i]--){
			for(int pi=w;pi>=p[i];pi--){
				for(int li=t;li>=l[i];li--){
					dp[pi][li]=max(dp[pi][li],dp[pi-p[i]][li-l[i]]+b[i]);
				}
			}
		}
	}
	cout<<dp[w][t]<<endl;
}

signed main(){
    freopen("hui.in","r",stdin);
    freopen("hui.out","w",stdout);
	// int T; cin>>T; while(T--)
	solve();
}

C题






模拟题,直接模拟即可,注意一下pow会爆,要自己写 \(10^n\) ,右边补一就 n*=10,n++ 即可,左边补 3 就直接加 \(3\times 10^{len+i-1}\)

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

using namespace std;

const int mod = 1e9 + 7;

int x;

void solve(){
	cin>>x;
	int cs = x;
	for(int k = 1;k<=cs;k++){
		int cnt0 = 0,cnt1 = 0,cnt2 = 0,cnt3 = 0;
		int tmp = x;
		while(tmp){
			if(tmp % 10 == 0) cnt0++;
			else if(tmp % 10 == 1) cnt1++;
			else if(tmp % 10 == 2) cnt2++;
			else if(tmp % 10 == 3) cnt3++;
			tmp/=10;
		}
		for(int i = 1;i<=cnt0;i++) x*=10,x++;
		for(int i = 1;i<=cnt1;i++) x*=2;
		tmp = x;
		int len = 0;
		while(tmp)len++,tmp/=10;
		for(int i = 1;i<=cnt2;i++){
			int add = 3;
			for(int j = 1;j<=len+i-1;j++) add *= 10;
			x += add;
		}
		if(cnt3) x += 123456;
		x += k;
		x %= mod;
		// cout<<x<<endl;
	}
	cout<<x<<endl;
}

signed main(){
    freopen("all.in","r",stdin);
    freopen("all.out","w",stdout);
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}

D题




双指针题,考虑每一种类的每个人都扔到一个数组里,然后双指针维护即可,种类数 \(< n\) 右边界右移,否则左边界右移,种类数达到 \(n\) 更新答案最小值,极差使用 set 进行维护(要重载运算符)

下面的代码只有 \(70\) 分,不知道挂哪了,待调。

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

using namespace std;

const int N = 1e6 + 3;

int n;
int vis[N];

struct node{
	int c,t;
	bool operator <(const node &x)const{
		return t < x.t;
	}
};
vector<node> a;
set<node> s;

bool cmp(node x,node y){
	return x.t < y.t;
}

void solve(){
	cin>>n;
	for(int i = 1;i<=n;i++){
		int ci; cin>>ci;
		for(int j = 1;j<=ci;j++){
			int t; cin>>t;
			a.push_back((node){i,t});
		}
	}
	sort(a.begin(),a.end(),cmp);
	int l = 0,r = 0;
	int ans = LONG_LONG_MAX;
	int kind = 0;
	while(l <= r && r<a.size()){
		if(kind<n){
			r++;
			s.insert(a[r-1]);
			vis[a[r-1].c]++;
			if(vis[a[r-1].c] == 1) kind++;
		} else {
			auto it = s.end(); it--;
			node ma = *it;
			node mi = *s.begin();
			ans = min(ans,ma.t - mi.t);
			s.erase(a[l]);
			vis[a[l].c]--;
			if(!vis[a[l].c]) kind--;
			l++;
		}
	}
	cout<<ans<<endl;
}

signed main(){
    freopen("buhezuo.in","r",stdin);
    freopen("buhezuo.out","w",stdout);
	// int T; cin>>T; while(T--)
	solve();
	return 0;
}
posted @ 2024-10-02 12:03  MNNUACM_2024ZY  阅读(31)  评论(0编辑  收藏  举报