Bootstrap

SMU Summer 2024 Contest Round 7

Make Equal With Mod

https://codeforces.com/problemset/problem/1656/C

我们可以看题,我们要选择一个大于等于2的整数X,用数组中的数除以X的余数,来替换原数组中的每个数。用来使数组中的数都相等。

我们可以判断出,1和2,1和0这两个组合在题目要求的情况下是矛盾的,因为他们取余任何数都不会彼此相等。那么我们可以从这里出发。在以上两种情况排除的前提下,你可以看到如果数组中没有1的存在,那么所有的数都可从大到小和自身进行取模,然后全部的数都可以变成0,如果数组中有1的存在,如果没有两两相差1的组合存在,那么所有的数都可以和比自身小一的数取模,然后变成1,这样,我们都可以让数组都等于一个数。那么仅剩的情况是哪个呢,1存在,并且存在两两之间相差一的组合。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf1 0x3f3f3f3f
#define inf2 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define PI acos(-1.0)
const int mod=1e9+7;
const int N=25;
int dp[10005];
void solve() {
	
	int n;
	cin>>n;
	
	vector<int>a(n+1);
	int k=1;
	
	map<int,int>u;
	
	for(int i=1;i<=n;i++){
		cin>>a[i];
		u[a[i]]++;
		if(a[i]!=a[i-1] and i>1){
			k=0;
		}
	}
	
	if(k==1){
		cout<<"YES"<<endl;
		return;
	}
	
	sort(a.begin()+1,a.end());
	
	if((u[0]!=0 and u[1]!=0) or (u[1]!=0 and u[2]!=0)){
		cout<<"NO"<<endl;
		return;
	}
	k=0;
	for(int i=1;i<=n;i++){
		if(a[i]!=1 and a[i-1]!=1 and a[i]==a[i-1]+1 and i>1){
			k=1;
		}
	}
	
	if(k==1 and u[1]!=0){
		cout<<"NO"<<endl;
		return;
	}
	cout<<"YES"<<endl;
	
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

B. Game on Ranges

https://codeforces.com/problemset/problem/1623/B

这个题是div2的B题,所以不用怕,尽管我也有第一题WA 5 发,然后第二题抑郁,最后-70的情况,但是不用怕。

这些数字最后都是要从原数组里被逐一挑出的。我们先把所有的数都标记一下,等到把一个数字判断已经被挑出后,就从标记里把这个数给抹除,我们可以用map来实现这个操作。

我们先把题目中的整个范围来进行排序。范围小的在前,大的在后面。这样可以把范围中只有一个数的情况给提前判断出,避免之后的影响。那之后就是对于数组中的数,哪个没有被抹除过,哪个就去输出就好了,边输出边去抹除标记。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf1 0x3f3f3f3f
#define inf2 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define PI acos(-1.0)
const int mod=1e9+7;
const int N=25;

struct ju{
	int l,r;
};

bool cmp(ju a,ju b){
	return abs(a.r-a.l)<(b.r-b.l);
}

void solve() {
	
	int n;
	cin>>n;//[1,n]
	vector<ju>a(n);
	map<int,int>u;
	for(int i=1;i<=n;i++){
		u[i]++;
	}
	for(int i=0;i<n;i++){
		cin>>a[i].l>>a[i].r;
		
	}
	sort(a.begin(),a.end(),cmp);
	for(int i=0;i<n;i++){
		cout<<a[i].l<<" "<<a[i].r<<" ";
		if(u[a[i].l]!=0){
			cout<<a[i].l<<endl;
			u[a[i].l]=0;
			continue;
		}if(u[a[i].r]!=0){
			cout<<a[i].r<<endl;
			u[a[i].r]=0;
			continue;
		}
		for(int j=a[i].l;j<=a[i].r;j++){
			if(u[j]!=0){
				cout<<j<<endl;
				u[j]=0;
				break;
			}
		}
	}
	cout<<endl;
	
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

Buy an Integer

C - Buy an Integer

二分判断,记得题目中左右边界的限定最多就到1e9了,很平常的二分做法,建立check函数来进行判断。

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
#define endl '\n'
#define inf1 0x3f3f3f3f
#define inf2 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
const int mod=1e9+7;
const int N=200005;
int a,b,x;
bool check(int c){
	int n=0;
	int c1=c;
	while(c1>0){
		c1/=10;
		n++;
	}
	int z=a*c+b*n;
	//cout<<z<<endl;
	if(z<=x){
		return true;
	}else{
		return false;
	}
}

void solve() {

	cin>>a>>b>>x;
	//a*n+b*d(n)//d(n)位数。	
	int l=0,r=1e9;
	int ans=0;
	while(l<=r){
		int mid=l+(r-l)/2;
		if(check(mid)){
			l=mid+1;
			ans=mid;
		}else{
			r=mid-1;
		}
	}
	cout<<ans<<endl;
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
//	cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

String Formation

D - String Formation

题目的要求很简单,但时间复杂度很很高,所以简单的模拟会超时。同样我们可以利用不寻常一点的方法,对于每个插入要求,我们单独建立两个字符串来记录开头和结尾的插入情况,对于翻转要求,我们利用一个标记,每次反转将这个标记进行0,1转换,用来适应反转后的插入状况,如果是一开始没有反转,那么我们就在记录开头的字符串插入就好,但每次反转后,我们都要用记录尾部的字符串来插入开头的字符。用记录开头的字符串来记录末尾。最后再根据反转情况调整一下输出就好了。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf1 0x3f3f3f3f
#define inf2 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define PI acos(-1.0)
const int mod=1e9+7;
const int N=25;
int dp[10005];
void solve() {
	
	string s;
	cin>>s;
	
	int q;
	cin>>q;
	string s1="",s2="";
	int k=0;
	for(int i=0;i<q;i++){
		int t;
		cin>>t;
		if(t==1){
			if(k==1){
				k=0;
			}else{
				k=1;
			}
		}
		if(t==2){
			int f;
			char c;
			cin>>f>>c;
			if(f==1){
				if(k==0){
					s1=c+s1;
				}else{
					s2=s2+c;
				}
			}else{
				if(k==0){
					s2=s2+c;
				}else{
					s1=c+s1;
				}
			}
		}
	}
	if(k==1){
		for(int i=s2.size()-1;i>=0;i--){
			cout<<s2[i];
		}
		for(int i=s.size()-1;i>=0;i--){
			cout<<s[i];
		}
		for(int i=s1.size()-1;i>=0;i--){
			cout<<s1[i];
		}
	}else{
		cout<<s1;
		cout<<s;
		cout<<s2;
	}
	
	
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

[ABC225F] String Cards

这个题并非是简单的排序。

我们用动态规划来解决它,我们可以令 fij等于从 i∼n 中取 j 个的最小排列,然后我们就能发现好像需要排序,那么怎么排呢?我们其实只需要按照能够有效保留一个相对大小关系并且不会出现以上情况的一种排序方式就行了,那么就为 Si+Si+1<Si+1+Si。

那么状态转移方程是什么呢?我们发现 fij只能从 fi+1,j​ 以及 fi+1,j−1 推导过来,然而 fi+1,j−1 我们还需要加上一个 Si​ 并且 Si 是加在 fi+1,j−1​ 前面的,然后将这两个取个最小值即可,但是有一个问题就是 fi+1,j 不一定有值,所以还要特判一下即可。而且 i 要是倒着循环的,毕竟前面说了 Si​ 要加在前面,最后的答案就为 f1,k​

#include<bits/stdc++.h>
using namespace std;
#define int long long
bool cmp(string a,string b){
    return a+b<b+a;
}
string dp[60][60];
string s[60];
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);
    int n,k;
    cin >> n >> k;
    for(int i = 1;i <= n; ++i)cin >> s[i];
    sort(s+1,s+n+1,cmp);
    for(int i = 1;i <= n; ++i){
        for(int j = 1;j <= k; ++j)dp[i][j] = "{";
    }
    dp[n][1] = s[n];
    for(int i = n-1;i >= 1; --i){
        for(int j = 1;j <= k; ++j){
            dp[i][j] = min(dp[i+1][j],s[i]+dp[i+1][j-1]);
        }
    }
    cout << dp[1][k] << endl;
    return 0;
}

;