什么破烂场,题目根本不是Div.2难度的。算了,写个题解再说吧。
Ranklist:
A - You’re given two binary strings…
题意:有两个01字符串 a a a和 b b b,如果把每个字符串看作一个二进制数的话,都会对应一个十进制数。字符串 s s s对应的十进制数记作 f ( s ) f(s) f(s)。你要求出满足要求的非负整数 k k k,使得 f ( a ) + 2 k ∗ f ( b ) f(a)+2^k*f(b) f(a)+2k∗f(b)转化为二进制后反序的字典序尽可能小。题目包含多测。
思路:
刚上来就给你一个下马威,告诉你这不是普通的Div.2.
首先,我们知道,乘
2
2
2的
k
k
k次方其实就是在二进制数后面添
k
k
k个
0
0
0,而如果要让反序的字典序尽可能小,那么最后一位就要尽可能小,在满足这个的前提下,倒数第二位也要尽可能小,以此类推。
我们假设
b
b
b的后
x
x
x位全部都是
0
0
0,而从右往左数第
x
x
x位为
1
1
1。那么
k
k
k不论取什么值,
f
(
a
)
+
2
k
∗
f
(
b
)
f(a)+2^k*f(b)
f(a)+2k∗f(b)的后
x
x
x位永远不会发生改变,永远与
a
a
a的后
x
x
x位相同。此时,如果第
a
a
a的第
x
x
x位为
1
1
1,那么我们就不用添
0
0
0了,已经取到了最优解。而如果如果第
a
a
a的第
x
x
x位为
0
0
0,那么
f
(
a
)
+
2
k
∗
f
(
b
)
f(a)+2^k*f(b)
f(a)+2k∗f(b)的第
x
x
x位为
1
1
1,不是我们想要的。此时我们就要在
b
b
b的后面添上一个
0
0
0,然后重复上述操作。
简单来说,假设
b
b
b最右边一个
1
1
1是从右往左数第
x
x
x位,那么本题要求的答案就是
a
a
a从右往左数第
x
x
x位左边有多少个连续的
0
0
0。
C o d e : Code: Code:
#include <bits/stdc++.h>
using namespace std;
int T;
string s,t;
int main(){
cin>>T;
while(T--){
cin>>s>>t;
int ind=-1;
for(int i=t.size()-1,cnt=0;i>=0;i--,cnt++){
if(t[i]=='1'){
ind=cnt;
break;
}
}
if(ind==-1){
cout<<0<<endl;
continue;
}
int ans=0;
for(int i=s.size()-ind-1;i>=0;i--){
if(s[i]=='0') ans++;
else break;
}
cout<<ans<<endl;
}
return 0;
}
B - You’re given a decimal string…
题意:给你一个由 0 0 0到 9 9 9组成的字符串。对于所有的 x = 0 , 1 , … , 9 x=0,1,\dots,9 x=0,1,…,9, y = 0 , 1 , … , 9 y=0,1,\dots,9 y=0,1,…,9,问你最少添加多少个数码使得相邻两个数码的差 m o d 10 mod\ 10 mod 10要么等于 i i i,要么等于 j j j,数码可以在任意位置添加。
思路:
思维难度没有上一题大,但是实现起来细节很恶心。
首先先
O
(
1
0
5
)
O(10^5)
O(105)预处理出在
0
0
0和
k
k
k之间最少添加多少个数码使得相邻两个数码的差
m
o
d
10
mod\ 10
mod 10要么等于
x
x
x,要么等于
y
y
y,用
a
x
,
y
,
k
a_{x,y,k}
ax,y,k记录。然后暴力即可。但是有一个非常恶心的坑点:相邻两个字符相同的情况要特判。这也就是为什么现场很多人WA
2
2
2,从而没有过这道题的原因。我比赛的时候也在这里死了好几次。
C o d e : Code: Code:
#include <bits/stdc++.h>
using namespace std;
string s;
int a[11][11][11],ans[11][11];
signed main(){
cin>>s;
memset(ans,0,sizeof(ans));
memset(a,63,sizeof(a));
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
for(int k=0;k<10;k++){
for(int p=0;p<=10;p++){
for(int q=0;q<=10;q++){
if((i*p+j*q)%10==k){
int x=k;
if(x==0) x=10;
if(x==10&&(p==0&&q==0)) continue;
a[i][j][x]=min(a[i][j][x],p+q);
}
}
}
}
for(int i=0;i<s.size()-1;i++){
int dig1=s[i]-'0',dig2=s[i+1]-'0';
int dif=(dig2-dig1+20)%10;
if(dif==0) dif=10;
for(int j=0;j<10;j++){
for(int k=0;k<10;k++){
if(~ans[j][k]){
if(a[j][k][dif]==0x3f3f3f3f) ans[j][k]=-1;
else ans[j][k]+=a[j][k][dif]-1;
}
}
}
}
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
C - You’re given a WASD string…
题意:有一个由“WASD"组成的字符串 s s s,代表机器人的移动命令。"W"表示向上移动一格,"A"表示向左移动一格,"S"表示向下移动一格,"D"表示向右移动一格。这个机器人的轨迹可以被一个矩形正好包围,现在允许你在 s s s的任意位置添上"WASD"中的一个字符,也可以不添,形成一个新的指令,使得这个矩形的面积尽可能小。题目包含多测。
思路:
我的做法可能和大家不太一样。
前缀和+线段树。首先我们先用前缀和将进行完第
i
i
i个指令之后机器人的位置求出来。我们记
s
u
m
i
,
0
sum_{i,0}
sumi,0表示进行完第
i
i
i个指令之后机器人的横坐标,
s
u
m
i
,
1
sum_{i,1}
sumi,1表示进行完第
i
i
i个指令之后机器人的纵坐标。因此矩形的面积就是
S
=
(
m
a
x
(
s
u
m
[
1
]
[
0
]
,
s
u
m
[
2
]
[
0
]
,
…
,
s
u
m
[
n
]
[
0
]
,
0
)
−
m
i
n
(
s
u
m
[
1
]
[
0
]
,
s
u
m
[
2
]
[
0
]
,
…
,
s
u
m
[
n
]
[
0
]
,
0
)
+
1
)
∗
(
m
a
x
(
s
u
m
[
1
]
[
1
]
,
s
u
m
[
2
]
[
1
]
,
…
,
s
u
m
[
n
]
[
1
]
,
0
)
−
m
i
n
(
s
u
m
[
1
]
[
1
]
,
s
u
m
[
2
]
[
1
]
,
…
,
s
u
m
[
n
]
[
1
]
,
0
)
+
1
)
;
S=(max(sum[1][0],sum[2][0],\dots,sum[n][0],0)-min(sum[1][0],sum[2][0],\dots,sum[n][0],0)+1)*(max(sum[1][1],sum[2][1],\dots,sum[n][1],0)-min(sum[1][1],sum[2][1],\dots,sum[n][1],0)+1);
S=(max(sum[1][0],sum[2][0],…,sum[n][0],0)−min(sum[1][0],sum[2][0],…,sum[n][0],0)+1)∗(max(sum[1][1],sum[2][1],…,sum[n][1],0)−min(sum[1][1],sum[2][1],…,sum[n][1],0)+1);
而我们枚举每一个位置
i
i
i,在第
i
i
i个位置后面添上一个’W’其实就是
s
u
m
i
,
1
=
s
u
m
i
−
1
,
1
+
1
,
s
u
m
i
+
1
,
1
=
s
u
m
i
,
1
+
1
,
s
u
m
i
+
2
,
1
=
s
u
m
i
+
1
,
1
+
1
,
…
s
u
m
n
+
1
,
1
=
s
u
m
n
,
1
sum_{i,1}=sum_{i-1,1}+1,sum_{i+1,1}=sum_{i,1}+1,sum_{i+2,1}=sum_{i+1,1}+1,\dots sum_{n+1,1}=sum_{n,1}
sumi,1=sumi−1,1+1,sumi+1,1=sumi,1+1,sumi+2,1=sumi+1,1+1,…sumn+1,1=sumn,1,其他也一样,这个可以用线段树来维护。
C o d e : Code: Code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
int T;
string s;
int sum[200005][2];
struct seg{
struct node{
int l,r,mn,mx,lz;
} s[800005];
inline void build(int k,int l,int r,int type){
s[k].l=l;s[k].r=r;
if(l==r){
s[k].mn=s[k].mx=sum[l][type];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid,type);
build(k<<1|1,mid+1,r,type);
s[k].mn=min(s[k<<1].mn,s[k<<1|1].mn);
s[k].mx=max(s[k<<1].mx,s[k<<1|1].mx);
}
inline void pushdown(int k){
s[k<<1].mx+=s[k].lz;
s[k<<1].mn+=s[k].lz;
s[k<<1].lz+=s[k].lz;
s[k<<1|1].mx+=s[k].lz;
s[k<<1|1].mn+=s[k].lz;
s[k<<1|1].lz+=s[k].lz;
}
inline void change(int k,int l,int r,int val){
if(l>r) return;
if(l<=s[k].l&&s[k].r<=r){
s[k].lz+=val;
s[k].mx+=val;
s[k].mn+=val;
return;
}
pushdown(k);
int mid=(s[k].l+s[k].r)>>1;
if(r<=mid) change(k<<1,l,r,val);
else if(l>mid) change(k<<1|1,l,r,val);
else change(k<<1,l,mid,val),change(k<<1|1,mid+1,r,val);
s[k].mn=min(s[k<<1].mn,s[k<<1|1].mn);
s[k].mx=max(s[k<<1].mx,s[k<<1|1].mx);
}
inline int query_mn(){
return s[1].mn;
}
inline int query_mx(){
return s[1].mx;
}
} st[2];
int area(){
return (max(st[0].query_mx(),0ll)-min(st[0].query_mn(),0ll)+1)*(max(st[1].query_mx(),0ll)-min(st[1].query_mn(),0ll)+1);
}
signed main(){
cin>>T;
while(T--){
cin>>s;
s=" "+s;
for(int i=0;i<=s.size();i++) sum[i][0]=sum[i][1]=sum[i][2]=sum[i][3]=0;
for(int i=1;i<s.size();i++){
sum[i][0]=sum[i-1][0];
sum[i][1]=sum[i-1][1];
if(s[i]=='W') sum[i][0]++;
if(s[i]=='A') sum[i][1]--;
if(s[i]=='S') sum[i][0]--;
if(s[i]=='D') sum[i][1]++;
}
st[0].build(1,1,s.size()-1,0);
st[1].build(1,1,s.size()-1,1);
int ans=area();
for(int i=0;i<=s.size();i++){
st[0].change(1,i,s.size()-1,-1);
ans=min(ans,(max(st[0].query_mx(),0ll)-min(st[0].query_mn(),min(sum[i-1][0]-1,0ll))+1)*(max(st[1].query_mx(),0ll)-min(st[1].query_mn(),0ll)+1));
st[0].change(1,i,s.size()-1,1);
st[0].change(1,i,s.size()-1,1);
ans=min(ans,(max(st[0].query_mx(),max(sum[i-1][0]+1,0ll))-min(st[0].query_mn(),0ll)+1)*(max(st[1].query_mx(),0ll)-min(st[1].query_mn(),0ll)+1));
st[0].change(1,i,s.size()-1,-1);
st[1].change(1,i,s.size()-1,-1);
ans=min(ans,(max(st[0].query_mx(),0ll)-min(st[0].query_mn(),0ll)+1)*(max(st[1].query_mx(),0ll)-min(st[1].query_mn(),min(sum[i-1][1]-1,0ll))+1));
st[1].change(1,i,s.size()-1,1);
st[1].change(1,i,s.size()-1,1);
ans=min(ans,(max(st[0].query_mx(),0ll)-min(st[0].query_mn(),0ll)+1)*(max(st[1].query_mx(),max(sum[i-1][1]+1,0ll))-min(st[1].query_mn(),0ll)+1));
st[1].change(1,i,s.size()-1,-1);
}
cout<<ans<<endl;
}
return 0;
}
题意:给定一个正整数 n n n,让你构造出一个由"1",“3”,“7"组成的字符串,其中恰好含有 n n n个字串"1337”。题目包含多测。
思路:
这道题可谓是有些毒瘤了,分明是水题,还不放在A或者B题,偏偏跑到个D的位置来,害得我现场做完C没时间做D。
很容易想到
133...33733...33733...337
133...33733...33733...337
133...33733...33733...337的情况,然后随便乱搞搞就行了,水题不多说。
C o d e : Code: Code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
vector<int> ans;
signed main(){
int T;cin>>T;
while(T--){
int n;cin>>n;
ans.clear();
putchar('1');
for(int i=50005;i>=1;i--){
while(n>=(i*(i+1)/2)){
ans.push_back(i+1);
n-=i*(i+1)/2;
}
}
sort(ans.begin(),ans.end());
for(int i=1;i<=ans[0];i++) putchar('3');putchar('7');
for(int i=1;i<ans.size();i++){
for(int j=1;j<=ans[i]-ans[i-1];j++)
putchar('3');
putchar('7');
}
cout<<endl;
}
}
有巨佬会E或者F的在洛谷上发私信给我,我的洛谷账号是这个,或者在下面评论哦!