2022 International Collegiate Programming Contest, Jinan Site

题目链接:2022年ICPC区域赛济南站

K. Stack Sort

解析:
根据题目意思,每次会将一个栈里的元素弹尽,也就是说我们得让一个栈里元素全是相邻的,且大数先进。
那可以我们先用map存下每个数在数组中的位置。
然后从2枚举到n,判断i的位置与i-1的位置。
首先开始得开一个栈。
如果i-1位置在i后面,说明这时i不用单开一个栈,反之需要多开一个。
所以答案就是统计多少个i在i-1前⾯。

#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ull unsigned long long
#define double long double
#define int long long
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e6 + 7;
const int P = 131;

int n, k;
int a[N];
void solve()
{
	int n;
	cin>>n;
	map<int,int>mp;
	for (int i=1;i<=n;i++){
		cin>>a[i];
		mp[a[i]]=i;
	}   
	int ans=1;
	for (int i=2;i<=n;i++){
		if (mp[i]>mp[i-1]){
			ans+=1;
		}
	}
	cout<<ans<<"\n";
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);

    int T;
    T = 1;
     cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

Best Carry Player

解析:
因为无论怎么变换顺序,最后答案都是一样的,进位也是一样的,所以进位次数与顺序无关,因此正常用高精加的方法做就行。

/*
 * @Author: Zhouzw
 * @LastEditTime: 2024-08-27 15:39:48
 */
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ull unsigned long long
#define double long double
#define int long long
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e6 + 7;
const int P = 131;
int wei1[401],wei2[401];
int cal(int x,int y){
	int cnt=0;
	for (int i=1;i<40;i++){
		wei1[i]=0;
		wei2[i]=0;
	}
	for (int i=1;i<40;i++){
		wei1[i]=x%10;
		x/=10;
	}
	for (int i=1;i<40;i++){
		wei2[i]=y%10;
		y/=10;
	}
	int jin=0;
	for (int i=1;i<40;i++){
		wei1[i]=wei1[i]+wei2[i]+jin;
		if (wei1[i]>=10){
			jin=1;
			cnt+=1;
		}else{
			jin=0;
		}
	}
	return cnt;
}
void solve()
{
	int n;
	cin>>n;
	int sum=0,ans=0;
	for (int i=1;i<=n;i++){
		int x;
		cin>>x;
		ans+=cal(sum,x);
		sum+=x;
	}
	cout<<ans<<"\n";
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T;
    T = 1;
     cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

E. Identical Parity

解析:
这道题赛时过了很多人,我觉得甚至比A、D难,题解看了很久才弄明白。
我们来求对于k来说,n符合的范围。
首先对于k为偶数的情况,因为可以奇数和偶数间隔排完,是恒可以的。
对于k为奇数的情况,我们先假设一组长度为k的序列为x,这样一共n/k组拼起来肯定是好的长序列。
但是因为k为奇数,所以一组长度为k的序列x肯定会多一个奇或偶。
总的奇数肯定是大于等于偶数的,所以我们让奇数多一个,这样n/k组会多n/k个奇数。
所以我们需要用连续n/k-1个偶数补在后面,这样整个序列肯定是好的,而且奇数正好比偶数多一个,也就是符合要求n的最小值。这时我们构造的序列x肯定会以至少t-1个偶数开始,并且t-1<=x。
接下来最大范围,也就是把k/2中剩下的0都用上,然后将相同数量的1也都用上。也就是0 1 0 1这样补,剩下0的数量最多也就是k/2-(t-1),因此能补的1数量也就是k/2-(t-1)。因此n的最大范围是n/k*k+t-1+k/2-(t-1)+k/2-(t-1).
比如n=30,k=9.那么序列可以是
000011111 0000111111 000011111 000
如果n是31,k=9,那么序列是
000101111 000101111 000101111 0001
如果n是33,k=9,那么序列是
000101111 000101111 000101111 000101
而n=29,k=9,是最小情况
000011111 0000111111 000011111 00
也就是在符合要求下每次多一个单个序列x就会0 1 0 1这样构造.

/*
 * @Author: Zhouzw
 * @LastEditTime: 2024-08-27 15:39:48
 */
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ull unsigned long long
#define double long double
#define int long long
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N=1000;
void solve() {
	int n,k;
	cin>>n>>k;
	if (k==1) {
		if (n==1){
			cout<<"Yes\n";
		}else{
			cout<<"No\n";
		}
	} else if (k%2==0) {
		cout<<"Yes\n";
	} else {
		int t=n/k;
		int x=k/2;
		if (x<t-1) {
			cout<<"No\n";
			return;
		}
		if (t*k+t-1<=n&&n<=t*k+(t-1)+x-(t-1)+x-(t-1)) {
			cout<<"Yes\n";
		} else {
			cout<<"No\n";
		}
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T;
	T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

A. Tower

解析:
我们要把所有的塔变成一个高度,如果不考虑除2这个操作,那么肯定选择中位数操作最优。
而多了除2这个操作会有什么影响呢,有一些大数变为小数通过这个操作会更快。
VP时看到这个n是500,那么肯定是n的平方外面加个t,因此复杂度就是50050010,然后再加/2的log感觉复杂度很符合。
差不多就想到,枚举一个高度,然后计算其他塔到这个塔的高度的最小操作数,去掉最多的m个。
如果这个塔高于最终高度,我们就需要先就进行除2操作,然后再慢慢减一。
但是枚举的高度怎么确定呢,因为有了除2操作,所以我们可能选小数更快,而不去选中位数,比如2,3,100,100,100。
因此每一个塔的高度都可以是最终的高度,其次向下除2还有有个向下取整的问题,比如4,10,10,10这种情况,我们选5肯定是最优的。因此我们还要将每一个塔除2直到0的高度进行枚举。

/*
 * @Author: Zhouzw
 * @LastEditTime: 2024-08-27 15:39:48
 */
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ull unsigned long long
#define double long double
#define int long long
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N=1000;
int a[N];
void solve() {
	int n,m;
	cin>>n>>m;
	vector<int>v;
	for (int i=1; i<=n; i++) {
		cin>>a[i];
		int x=a[i];
		while (x>0) {
			v.push_back(x);
			x/=2;
		}
	}
	int mn=1e18;
	for (int i=0; i<v.size(); i++) {
		int ans=0;
		vector<int>vv;
		for (int j=1; j<=n; j++) {
			if (a[j]<=v[i]) {
				int cnt=v[i]-a[j];
				vv.push_back(cnt);
			} else {
				int cnt=0;
				int x=a[j];
				while (x/2>=v[i]) {
					x/=2;
					cnt+=1;
				}
				cnt+=min(x-v[i],v[i]-x/2+1);
				vv.push_back(cnt);
			}
		}
		sort(vv.begin(),vv.end());
		int x=vv.size();
		for (int k=0; k<vv.size()-m; k++) {
			ans+=vv[k];
		}
		if (mn>ans) {
			mn=min(mn,ans);
		}
	}
	cout<<mn<<'\n';
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T;
	T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

Frozen Scoreboard

解析:
首先先将已经确定通过的题和罚时减去,剩下还需要过的题a和罚时b。
接下来就是可能会有13个不确定的题,向其中选7道。
我们可以使用二进制枚举,从1枚举到(1<<m),其中如果有a个1,并且1的位置不包含本身就过了的题,那么我们就可以判断它的罚时是否符合。
罚时也是有一个范围的。最小肯定就是封榜后240的时候一发过,最坏就是第299分钟的时候y-1才过,这时可以计算出这a道题总共的最小罚时mn,最大罚时mx,如mn<=b<=mx,那就是符合的。
符合之后我们就需要判断,具体的每一道题需要什么时候通过,封榜后提交多少次。
我们可以先将b-mn。
这时我们遍历将每一道题的提交次数拉满,cs=min(b/20,x-1),以及时间也这样修改,sj=min(b,59).

/*
 * @Author: Zhouzw
 * @LastEditTime: 2024-08-27 15:39:48
 */
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define ull unsigned long long
#define double long double
#define int long long
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N=1000;
int a,b;
int cnt;
struct Node {
	char op;
	int x,y;
} node[N];
int n,m;
int flag[N];
int tim[N];
void input() {
	for (int i=0; i<m; i++) {
		flag[i]=0;
		tim[i]=0;
		cin>>node[i].op;
		if (node[i].op=='+') {
			int cs=0,sj=0,dd=0;
			string s;
			cin>>s;
			for (int j=0; j<s.size(); j++) {
				if (s[j]=='/') {
					dd=j;
					break;
				}
				cs=cs*10+s[j]-'0';
			}
			for (int j=dd+1; j<s.size(); j++) {
				sj=sj*10+s[j]-'0';
			}
			node[i].x=cs;
			node[i].y=sj;
			b=b-(node[i].x-1)*20-node[i].y;
			a-=1;
			flag[i]=1;
		} else if (node[i].op=='-') {
			cin>>node[i].x;
		} else if (node[i].op=='.') {
			continue;
		} else {
			flag[i]=4;
			cin>>node[i].x>>node[i].y;
			node[i].x=node[i].y-node[i].x;
		}
	}
}
int check() {
	if (a<0||b<0) {
		return 0;
	}
	//cout<<(1<<m)<<"****"<<'\n';
	for (int i=0; i<(1<<m); i++) {
		int num=0;
		int vis=0;
		for (int j=0; j<m; j++) {
			if (((i>>j)&1)==0) {
				continue;
			}
			num+=1;
		}
		//cout<<b<<"***\n";
		if (num!=a) {
			continue;
		}
		for (int j=0; j<m; j++) {
			if (((i>>j)&1)==1&&flag[j]!=4) {//只保留有?的题
				vis=1;
				break;
			}
		}
		if (vis) {
			continue;
		}
		int mn=0,mx=0;
		for (int j=0; j<m; j++) {
			if (((i>>j)&1)==1) {
				mn+=(node[j].x*20)+240;
				mx+=(node[j].y-1)*20+299;
			}
		}
		if (b>=mn&&b<=mx) {
			b-=mn;
			for (int j=0; j<m; j++) {
				if (((i>>j)&1)==1) {
					int cs=min(b/20,node[j].y-node[j].x-1);
					node[j].x+=cs+1;
					b-=(cs*20);
					int sj=min(b,1ll*59);
					tim[j]=240+sj;
					b-=sj;
					flag[j]=1;
				}
			}
			return 1;
		}

	}
	return 0;
}
void print() {
	cout<<"Yes\n";
	for (int i=0; i<m; i++) {
		if (node[i].op=='+') {
			cout<<node[i].op<<" "<<node[i].x<<"/"<<node[i].y<<"\n";
		} else if (node[i].op=='-') {
			cout<<node[i].op<<" "<<node[i].x<<"\n";
		} else if (node[i].op=='.') {
			cout<<'.'<<'\n';
		} else {
			if (flag[i]==1) {
				cout<<"+ "<<node[i].x<<"/"<<tim[i]<<"\n";
			} else {
				cout<<"- "<<node[i].y<<"\n";
			}
		}
	}
}
void solve() {
	cin>>n>>m;
	for (int i=1; i<=n; i++) { //第i支队伍
		cin>>a>>b;
		input();
		if (check()) {
			print();
		} else {
			cout<<"No\n";
		}
	}

}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	int T;
	T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值