Codeforces Round #713(Div. 3) (全)

Codeforces Round #713(Div. 3)

A.Spy Detected!

题意:给定一个数组a,在a[ ]中只有一个数唯一,求这个数的位置

思路:纯模拟

Code:

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a; i<=n; i++)
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define int long long
#define pb push_back
#define fi first
#define sc second
#define pii pair<int,int>
using namespace std;
const int mxn=110;
int a[mxn], idx[mxn];
void solve(){
    int n;
    cin>>n;
    map<int,int> mp;
    rep(i,1,n) cin>>a[i], mp[a[i]]++, idx[a[i]]=i;
    for(auto &[x,y]:mp){
        if(y==1) {cout<<idx[x]<<'\n';return;}
    }
}
signed main(){
    ios;
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

B.Almost Rectangle

题意:给定一个字符矩阵,将 ∗ * 号所围成图形也补成一个矩阵

思路:找出 ∗ * 号位置,分类讨论一下即可

Code:

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a; i<=n; i++)
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define int long long
#define pb push_back
#define fi first
#define sc second
#define pii pair<int,int>
using namespace std;
const int mxn=450;
char a[mxn][mxn];
void solve(){
	int n;
	cin>>n;
	int x1, y1, x2, y2;
	int tag=0;
	rep(i,1,n){
		rep(j,1,n){
			cin>>a[i][j];
			if(a[i][j]=='*'){
				if(tag==0) x1=i, y1=j, tag=1;
				else x2=i, y2=j;
			}
		}
	}
	if(x1!=x2&&y1!=y2){
		a[x2][y1]='*';
		a[x1][y2]='*';
	}
	else{
		if(x1==x2){
			if(x1==n){
				a[1][y1]='*';
				a[1][y2]='*';
			}
			else{
				a[n][y1]='*';
				a[n][y2]='*';
			}
		}
		else{
			if(y1==n){
				a[x1][1]='*';
				a[x2][1]='*';
			}
			else{
				a[x1][n]='*';
				a[x2][n]='*';
			}
		}
	}
	rep(i,1,n){
		rep(j,1,n){
			cout<<a[i][j];
			if(j==n) cout<<'\n';
		}
	}
}
signed main(){
	ios;
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

C. A-B Palindrome

题意:给你一个由0,1,?三种字符组成的字符串s,对于每个?你可以用0/1代替作为一次操作,现要求你经过若干次操作后将原字符串s变成由a个0,b个1组成的回文字符串,若可行,输出结果字符串ans;无解则输出-1

思路:首先预处理一下整个字符串s,对于从左开始扫的字符和从右开始扫的字符中一个是?一个是0/1的情况,我们先将他们补充完整,并判断无解,后从左往右扫描一遍得到的字符串,对a与b的个数删减,接下来我们要处理的就是成对的问号,在这里我们只扫描左半边,并贪心的思考将max(a,b)对应的字符进行填补,同样删减a,b.然后最后对于字符串原长是奇数的情况,我们还剩一个 ?没有处理,对应的特判一下.

Code:

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a; i<=n; i++)
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define int long long
#define pb push_back
#define fi first
#define sc second
#define pii pair<int,int>
using namespace std;

void solve(){
	int a, b;
	cin>>a>>b;
	string s;
	cin>>s;
	int n=s.size();
	for(int i=0; i<n; i++){
		if(s[i]!='?'){
			if(s[n-i-1]=='?') s[n-i-1]=s[i];
			else if(s[n-i-1]!=s[i]){
				cout<<-1<<'\n';
				return ;
			}
		}
	}
	for(int i=0; i<n; i++){
		if(s[i]=='0') a--;
		else if(s[i]=='1') b--;
		if(a<0||b<0){
			cout<<-1<<'\n';
			return;
		}
	}
	for(int i=0; i<n-i-1; i++){
		if(s[i]=='?'){
			int t=max(a,b);
			if(t<=1) {cout<<-1<<'\n';return;}
			if(t==a){
				s[i]=s[n-i-1]='0';
				a-=2;
			}
			else{
				s[i]=s[n-i-1]='1';
				b-=2;
			}
		}
	}
	if((n&1)&&(s[n/2]=='?')){
		int t=max(a,b);
		if(t<1) {
			cout<<-1<<'\n';
			return ;
		}
		if(t==a) s[n/2]='0', a--;
		else s[n/2]='1', b--;
	}
	cout<<s<<'\n';
}
signed main(){
	ios;
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

D. Corrupted Array

题意:给你一个n+2长度的数组b,根据特定算法还原数组a,该算法要求: No1.b可以洗牌(顺序不影响结果)

No2. b i = a i ( 1 < = i < = n ) b_i=a_i(1<=i<=n) bi=ai(1<=i<=n) No3. b i + 1 = a 1 + a 2 + . . . + a n b_{i+1}=a_1+a_2+...+a_n bi+1=a1+a2+...+an No4. b 2 = x ( 1 < = x < = 1 0 9 ) b_2=x(1<=x<=10^9) b2=x(1<=x<=109) No5. a数组是推定的

有解输出序列a,无解输出-1

思路:因为有个数是其他数的前缀和,所以这个数肯定很大,考虑到 b i < = 1 0 9 b_i<=10^9 bi<=109 , 所以 a i < = 1 0 9 a_i<=10^9 ai<=109 , 然后可以大胆构造了

取b中最大值先作前缀和试试,接下来要在其余n+1个数找n个数使得它们的和等于这个前缀和,舍弃的那个数作x即可

若此时无解则继续尝试b的次大值作前缀和,b的最大值舍去(不舍去的话作为成员加入前缀和肯定比次大值大,相互矛盾,所以只能舍去), 在n+1中数中找n个数使其和等于次大值,所以次大值的2倍等于前n+1小的数的和,若不满足则无解

对于要是以b中第3大值(或者是第n大值, n > = 3 n>=3 n>=3)作为前缀和,那么次大值和最大值中只有一个作随机数,另一个必然加入前缀和的成员,又相互矛盾,所以不必继续讨论

Code:

#include<bits/stdc++.h>
#define int long long
#define rep(i,a,n) for(int i = a; i<=n; i++)
#define pb push_back
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int mxn=2e5+10;
int b[mxn], a[mxn];
auto solve()->void{
    int n;
    cin>>n;
    rep(i,1,n+2) cin>>b[i];
    vector<int> v;
    sort(b+1,b+n+3);
    int sum=0, lst=b[n+2];
    rep(i,1,n+1) sum+=b[i];
    int ansi=-1;
    rep(i,1,n+1){
        if(sum-b[i]==lst) {ansi=i;break;}
    }
    if(ansi!=-1){
        rep(i,1,n+1){
            if(i==ansi) continue;
            v.pb(b[i]);
        }
        for(int i=0; i<v.size(); i++) cout<<v[i]<<" \n"[i==v.size()-1];
        return;
    }
    if(b[n+1]==sum-b[n+1]){
        rep(i,1,n) cout<<b[i]<<" \n"[i==n];
        return;
    }
    cout<<-1<<'\n';
}
signed main(){
    ios;
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

E. Permutation by Sum

题意:给定整数n,l, r, s,要求你找一个长度为n的排列p使得 s = p l + p l + 1 + . . . + p r s=p_l+p_{l+1}+...+p_r s=pl+pl+1+...+pr, 若有多个则输出任意一个,若无解则输出-1

思路:对于所给区间[l,r],我们先特判 s m i n = 1 + 2 + . . . + p r − l + 1 s_{min}=1+2+...+p_{r-l+1} smin=1+2+...+prl+1 s m a x = p n + p n − 1 + . . . + p n − r + l s_{max}=p_n+p_{n-1}+...+p_{n-r+l} smax=pn+pn1+...+pnr+l的值与s的关系,若 s m i n < = s < = s m a x s_{min}<=s<=s_{max} smin<=s<=smax ,则先将区间[l,r]中的数依次赋为 s m i n s_{min} smin中的值,否则无论我们怎么调整区间[l,r]的数都是无解,

接下来我们按照一种类似于“进制”的思想,优先调整后端的数,若后端的数已达到最大,再调整前端的数,依次迭代,这样我们就处理好了区间[l,r]中的数,并对于这些数打上标记,最后对于整个排列,我们再将没有标记过的数依次塞入就行

Code:

#include<bits/stdc++.h>
#define int long long
#define rep(i,a,n) for(int i = a; i<=n; i++)
#define pb push_back
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int mxn=510;
int p[mxn], vis[mxn];
auto solve()->void{
    int n, l, r, s;
    cin>>n>>l>>r>>s;
    rep(i,1,n) vis[i]=0, p[i]=0;
    int mi=0, ma=0;
    rep(i,1,r-l+1) mi+=i;
    for(int i=n; i>=n-(r-l+1)+1; i--) ma+=i;
    if(s>ma||s<mi) {cout<<-1<<'\n';return;}
    s-=mi;//需要调整的差值
    rep(i,l,r) p[i]=i-l+1;
    for(int i=r; i>=l; i--){
        if(s>=n-(r-l+1)){
            s-=n-(r-l+1);
            p[i]+=n-(r-l+1);
            vis[p[i]]=1;
        }
        else{
            p[i]+=s;
            vis[p[i]]=1;
            s=0;
        }
    }
    rep(i,1,n){
        if(p[i]==0){
            rep(j,1,n){
                if(!vis[j]){
                    p[i]=j;
                    vis[j]=1;
                    break;
                }
            }
        }
    }
    rep(i,1,n) cout<<p[i]<<" \n"[i==n];
}
signed main(){
    ios;
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

F. Education

题意:Polycarp 想要买新电脑,新电脑价格为c,他可以通过任职来赚钱,其公司有n个职位,编号从1开始,初始状态时他有0元钱和处于1位置。

每一天,他都有2个选择:

No1. 在i位置上获得a[i]元钱 (赚钱)

No2. 花b[i]元钱移动位置到i+1 (升级)

问最少几天他可以买到电脑?

思路:大模拟,我们可以枚举第 i( 1 < = i < n 1<=i<n 1<=i<n)天的情况, 在赚钱和升级2种情况中取天数的最小值,可以先得到在当前i位置下需要多少天才能达到c,然后对于现在的钱要是可以升级,那就升级,若不能升级那就赚钱去升级,最后对于到达满级的情况单独特判一下,取最小值即可

Code:

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a; i<=n; i++)
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define int long long
#define pb push_back
#define fi first
#define sc second
#define pii pair<int,int>
using namespace std;
const int mxn=2e5+10, inf=LLONG_MAX;
int a[mxn], b[mxn];
int Ceil(int a,int b){
	if(a%b==0) return a/b;
	else return a/b+1;
}
void solve(){
	int n, c;
	cin>>n>>c;
	rep(i,1,n) cin>>a[i];
	rep(i,1,n-1) cin>>b[i];
	int mi=inf;
	int day=0;
	int money=0;
	for(int i=1; i<n; i++){
		int tm=Ceil(c-money,a[i]);
		mi=min(mi,day+tm);//不升级只赚钱
		if(money>=b[i]){//升级
			money-=b[i];
			day++;
		}
		else{//赚钱去升级
			int tm=Ceil(b[i]-money,a[i]);
			day+=tm;
			day++;
			money+=tm*a[i]-b[i];
		}
	}
	cout<<min(mi,day+Ceil(c-money,a[n]))<<'\n';
}
signed main(){
	ios;
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

G. Short Task

题意:我们先定义d(n) = n的所有因子之和,给定一个数c( 1 < = c < = 1 e 7 1<=c<=1e7 1<=c<=1e7),要求寻找最小的n满足d(n) = c

思路:预处理+打表,对于每个是i的倍数的数我们都要加上i,所以我们开个sum[ ]记录每个数的 d ( n ) d(n) d(n),然后再打个表记录一下第一次出现 d ( n ) d(n) d(n)时的n即可

Code:

#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std; 
const int mxn=1e7+5;
int sum[mxn];
int ans[mxn];
void pre(){
	for(int i=1; i<mxn; i++) ans[i]=-1;
	for(int i=1; i<mxn; i++){
		int num=i;
		while(num<mxn){
			sum[num]+=i;
			num+=i;
		}
	}
	for(int i=1; i<mxn; i++){
		if(sum[i]<mxn&&ans[sum[i]]==-1){
			ans[sum[i]]=i;
		}
	}
}
signed main(){
	ios;
	pre();
	int t=1;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		cout<<ans[n]<<'\n';
	}
	return 0;		
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值