Codeforces Round 1043 (Div. 3)(A-E)
补题链接:Dashboard - Codeforces Round 1043 (Div. 3) - Codeforces
A. Homework
思路
模拟就行了
代码
void solve(){int n;string a;cin>>n>>a;string t=a;a=" "+a;int m;string b;cin>>m>>b;b=" "+b;string s;cin>>s;int now=1;for(int i=0;i<s.size();i++){if(s[i]=='D'){t=t+b[now];}else{t=b[now]+t;}now++;}cout<<t<<"\n";
}
B. The Secret Number
思路
右边加0就是,即
,所以我们遍历一遍看n是否取余
为0即可
代码
void solve(){int n;cin>>n;int now=1;vi ans;for(int i=1;i<=18;i++){now*=10;int t=now+1;if(n%t==0){ans.push_back(n/t);}}sort(ans.begin(),ans.end());cout<<ans.size()<<"\n";for(int x:ans){cout<<x<<" ";}cout<<"\n";
}
C1. The Cunning Seller (easy version)
思路
我们要保证交易次数最少,因为每次可以交易的西瓜,对于n来说我们只需要每次找到最大的x然后让n来减去
,这样就能保证交易次数最少,如果不是每次找到最大的x那么我们应该至少需要3次来抵消掉此次操作,所以我们这样就是最小的交易次数
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;vi p(50,0);
void init(){p[0]=3;for(int i=1;i<=30;i++){p[i]=(9+i)*pow(3,i-1);}
}void solve(){int n;cin>>n;int ans=0;for(int i=30;i>=0;i--){int x=pow(3,i);while(n>=x){n-=x;ans+=p[i];}}cout<<ans<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);init();int _=1;cin>>_;while(_--) solve();return 0;
}
C2. The Cunning Seller (hard version)
思路
我们要保证最多k次交易的情况下交易n个西瓜,并且花费金币最少
我们可以从C1的基础上做文章,如果每多两次交易我们可以将西瓜从,西瓜数量不变但是金币的数量却减少了,发现x越大的所省下的金币越少,那么我们便以此为切入点,在C1所求出的最小交易次数的基础上变成k次,每多2次就让最大的x变成3个x-1
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;vi p(40,0);
vi pw(40,0);
void init(){pw[0]=1;for(int i=1;i<=25;i++){pw[i]=3*pw[i-1];}p[0]=3;for(int i=1;i<=25;i++){p[i]=(9+i)*pw[i-1];}}void solve(){int n,k;cin>>n>>k;if(k>=n){cout<<n*3<<"\n";return;}int cnt=0;int tn=n;vi ct(40,0);for(int i=25;i>=0;i--){int x=pw[i];while(tn>=x){tn-=x;cnt++;ct[i]++;}}if(k<cnt){cout<<"-1\n";return;}k-=cnt;int c=k/2;for(int i=25;i>=0;i--){if(c){if(c<=ct[i]){ct[i-1]+=3*c;ct[i]-=c;c=0;break;}else{ct[i-1]+=3*ct[i];c-=ct[i];ct[i]=0;}}else{break;}}int ans=0;for(int i=0;i<=25;i++){ans+=ct[i]*p[i];}cout<<ans<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);init();int _=1;cin>>_;while(_--) solve();return 0;
}
D. From 1 to Infinity
思路
此题我们肯定首先要定位加到某个数x,然后求从1->x的各位数之和以及(x+1)的前几位数相加
1.定位,这并不难实现,9个1位,90个2位,900个3位...,暴力定位即可
2.求1->x的各位数之和,这个学过数位dp的话应该不算太难
代码
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;int f(int n){ //从0到n的各位数字之和if(n<=0) return 0;if(n<10) return n*(n+1)/2;int x=1;int d=0;while(x*10<=n){x*=10;d++;}int a=n/x;int b=n%x;int td=d*45*(x/10);return a*td+x*a*(a-1)/2+a*(b+1)+f(b);
}void solve(){int k;cin>>k;//定位k位于那位数的加和上int d=1;int x=9;while(k-d*x>=0){k-=d*x;d++;x*=10;}int ans=0;int n=k/d;int r=k%d;int now=pow(10,d-1)+n-1; //求出加到哪个完整的数ans+=f(now);string s=to_string(now+1);for(int i=0;i<r;i++){ans+=(s[i]-'0');}cout<<ans<<"\n";
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}
E. Arithmetics Competition
思路
是个好题,有两种做法
做法一:
我们将a与b数组合成一个数组从大到小排序,对于每次询问x,y,z,我们用cnta表示前z大的中出现了cnta个a数组里面的数,cntb表示出现了cntb个b数组里面的数
1.cnta<=x&&cntb<=y 我们直接输出前z大的和即可
2.cnta>x 也就是我们从a中选择x个数,从b中选择z-x个数,可以保证这样是最大的
3.cntb>y 从b中选择y个数,从a中选择z-y个数
做法二:
我们将a从小到大排序,b从大到小排序,将a与b拼接
这样就形成了一个从小到大再从大到小的一个数组,我们每次询问的目的是找到从区间内选择一个长度为z的子区间求最大的子区间
发现子区间也是从小到大再由大到小的,那么我们就可以尝试用三分查找来找到最大的子区间的位置,进而得到答案
代码
一:
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;struct node{int v,id;
};
bool cmp(node x,node y){return x.v>y.v;
}void solve(){int n,m,q;cin>>n>>m>>q;vi a(n+1),b(m+1);for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=m;i++) cin>>b[i];sort(a.begin()+1,a.begin()+1+n,greater<int>());sort(b.begin()+1,b.begin()+1+m,greater<int>());vector<int> sa(n+1),sb(m+1); //前缀和for(int i=1;i<=n;i++) sa[i]=sa[i-1]+a[i];for(int i=1;i<=m;i++) sb[i]=sb[i-1]+b[i];vector<node> c(1);for(int i=1;i<=n;i++) c.push_back({a[i],1});for(int i=1;i<=m;i++) c.push_back({b[i],2});sort(c.begin()+1,c.begin()+1+n+m,cmp);vector<int> p(n+m+1); //记录前i个中a出现的次数for(int i=1;i<=n+m;i++){p[i]=p[i-1];if(c[i].id==1) p[i]++;}while(q--){int x,y,z;cin>>x>>y>>z;int cnta=p[z];int cntb=z-p[z];int ans=0;if(cnta<=x&&cntb<=y){ans=sa[cnta]+sb[cntb];}else if(cnta>x&&cntb<=y){ans=sa[x]+sb[z-x];}else if(cnta<=x&&cntb>y){ans=sa[z-y]+sb[y];}cout<<ans<<"\n";}
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}
二:
#include<bits/stdc++.h>
using namespace std;#define vcoistnt ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define int long long
#define vi vector<int>
#define vb vector<bool>
typedef pair<int,int> pll;const int N=2e5+10;
const int inf=1e18;
const int mod=998244353;void solve(){int n,m,q;cin>>n>>m>>q;vi a(n+1),b(m+1);for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=m;i++) cin>>b[i];sort(a.begin()+1,a.begin()+1+n);sort(b.begin()+1,b.begin()+1+m,greater<int>());vector<int> c(1);for(int i=1;i<=n;i++) c.push_back(a[i]);for(int i=1;i<=m;i++) c.push_back(b[i]);vi sum(n+m+1,0); //前缀和for(int i=1;i<=n+m;i++) sum[i]=sum[i-1]+c[i];while(q--){int x,y,z;cin>>x>>y>>z;auto f=[&](int x)->int{return sum[x+z-1]-sum[x-1];};int l=n-x+1,r=n+y-z+1;while(r-l>6){int lmid=l+(r-l)/3,rmid=r-(r-l)/3;if(f(lmid)>=f(rmid)) r=rmid;else l=lmid;}int ans=0;for(int i=l;i<=r;i++){ans=max(ans,f(i));}cout<<ans<<"\n";}
}
signed main() {vcoistntcout<<fixed<<setprecision(2);int _=1;cin>>_;while(_--) solve();return 0;
}