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+...+pr−l+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+pn−1+...+pn−r+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;
}