A. Prefixes
题意:
你每次可以将某个位置上的 a 改变为 b 或者将 b 改变为 a,使得对于所有偶数位置 i,[1,i] 的 a 的数量 = b 的数量
思路:
连续两个一样的,就将后一个改变为和前一个不一样。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=2e5+5;
int n,m,k;
char a[N],b[N];
int main(){
cin>>n;
scanf("%s",a+1);
int ans=0;
for(int i=2;i<=n;i+=2){
if(a[i]==a[i-1]){
ans++;
if(a[i]=='a')
a[i]='b';
else
a[i]='a';
}
}
cout<<ans<<endl<<a+1;
return 0;
}
B. Shooting
题意:
有 n 个物品,第 i 个物品有一个耐久度
a
i
a_{i}
ai,损坏它的花费为 x*
a
i
a_{i}
ai+1,其中 x 为之前损坏的物品数量,问损坏所有的物品的最小花费是多少以及顺序。
思路:
很明显,先损坏耐久度大的,直接根据耐久度排序就行。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=2e5+5;
int n,m,k;
#define P pair<int,int>
P p[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&p[i].first);
p[i].first*=-1;
p[i].second=i;
}
sort(p+1,p+1+n);
LL ans=0;
for(int i=1;i<=n;i++)
ans+=-p[i].first*(i-1)+1;
cout<<ans<<endl;
for(int i=1;i<=n;i++)
printf("%d ",p[i].second);
return 0;
}
C. White Sheet
题意:
给你3个矩形A,B,C , 问
B
⋃
C
B\bigcup C
B⋃C 是否完全覆盖A
思路:
这题可以直接一个一个if去判断(我不喜欢讨论就没用这种写法),观察发现可以从面积下手,
(
B
⋂
A
)
⋃
(
C
⋂
A
)
=
=
A
(B\bigcap A) \bigcup(C\bigcap A)==A
(B⋂A)⋃(C⋂A)==A 的话,则完全覆盖
S ( B ⋂ A ) ⋃ ( C ⋂ A ) = S ( B ⋂ A ) + S ( C ⋂ A ) − S ( ( B ⋂ A ) ) ⋂ ( C ⋂ A ) S_{(B\bigcap A) \bigcup(C\bigcap A)}= S_{(B\bigcap A) } + S_{(C\bigcap A)} - S_{((B\bigcap A))\bigcap (C\bigcap A)} S(B⋂A)⋃(C⋂A)=S(B⋂A)+S(C⋂A)−S((B⋂A))⋂(C⋂A)
两个矩形的交的话很好求。左下角取大,右上角取小就行。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define P pair<int,int>
const int N=2e8+5;
const LL INF=1e9;
const LL III=1e18;
int n,m;
int x[100],y[100];
void slove(int id1,int id2,int id3){
if(x[id1]>=x[id2+1]||y[id1]>=y[id2+1])
return ;
swap(id1,id2);
if(x[id1]>=x[id2+1]||y[id1]>=y[id2+1])
return ;
x[id3]=max(x[id1],x[id2]);
y[id3]=max(y[id1],y[id2]);
x[id3+1]=min(x[id1+1],x[id2+1]);
y[id3+1]=min(y[id1+1],y[id2+1]);
}
LL mj(int id){
return 1LL*(x[id+1]-x[id])*(y[id+1]-y[id]);
}
int main(){
for(int i=1;i<=6;i++)
scanf("%d%d",&x[i],&y[i]);
slove(1,3,7);
slove(1,5,9);
slove(7,9,11);
if((mj(7)+mj(9)-mj(11))!=mj(1))
puts("YES");
else
puts("NO");
return 0;
}
D. Swords
题意:
地宫开始有 n 总类型的剑,每种类型的剑有 x 个,有 y 个人冲进地宫,每个人只拿一种类型的剑并且拿 z 吧。第二天守卫来检查发现第 i 种类型的剑只剩下
a
i
a_{i}
ai 把,先给你 n 和 a,试确定最小的 y 并且确定 z 。
思路:
玄学,直接感觉
x
=
m
a
x
(
a
i
)
,
i
∈
[
1
,
n
]
x=max(a_{i}),i\in [1,n]
x=max(ai),i∈[1,n],然后直接求就行.
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=2e5+5;
int n,m,k;
#define P pair<int,int>
int a[N];
int main(){
cin>>n;
int ma=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
ma=max(a[i],ma);
}
LL y;
int z=0;
for(int i=1;i<=n;i++)
z=__gcd(z,ma-a[i]);
y=0;
for(int i=1;i<=n;i++)
if(ma!=a[i])
y+=(ma-a[i])/z;
printf("%lld %d\n",y,z);
return 0;
}
E2. Numerical Sequence (hard version)
题意:
给你个序列 11212312341234512345612345671234567812345678912345678910 ,问第k位。
分析:
考虑两个问题:
问题1: 1121231234…123…x 的长度是多少。(
x
∈
[
1
,
1
e
18
]
x\in [1,1e18]
x∈[1,1e18])
我们可以通过每个数字的次数轻松算出来(请注意,数字不是数位)。
设 len 为 x 的值的长度。
F(1) = x
…
F(9) = x-8
F(10) = x-9
…
F(99) = x-98
…
F(
1
0
l
e
n
−
1
10^{len-1}
10len−1) = x -
1
0
l
e
n
−
1
10^{len-1}
10len−1 +2
F(x) = 1
则规律以及出现,
长度为1的为 1-9 出现了 (x) + (x-1) + … + (x-8) 次
长度为2的为10-99 出现了 (x-9) + (x-10) + … + (x-98) 次
…
长度为len的为
1
0
l
e
n
−
1
−
x
10^{len-1}-x
10len−1−x 出现了
(
x
−
1
0
l
e
n
−
1
)
+
.
.
.
+
1
(x-10^{len-1}) + ... + 1
(x−10len−1)+...+1次
然后直接等差数列求和就行了,或者预处理好。
知道这个问题我门就可以二分,确定结尾那一块。
现在我们还需要得到他具体属于哪个数字。
问题2:一个序列1234…x的长度
这个也可以通过二分实现,通过枚举长度来check。最后就知道答案在那个数字里,以及在哪一位,这个很好写。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define P pair<int,int>
const int N=2e8+5;
const LL INF=1e9;
int n,m;
LL k;
LL fi[100];
int str(LL x){
if(x==0)return 0;
int len=0;
while(x)
len++,x/=10;
return len;
}
LL check(LL x){
if(x==0)return 0;
int len=str(x);
LL sum=0;
for(int i=1;i<len;i++)
sum+=(x-fi[i-1]+1 + x - fi[i] +2)*(fi[i]-fi[i-1])/2*i;
sum+=(x - fi[len-1] + 1 +1)*(x - fi[len-1] + 1)/2*len;
return sum;
}
LL check2(LL x){
if(x==0)return 0;
int len=str(x);
LL sum=0;
for(int i=1;i<len;i++)
sum+=9*fi[i-1]*i;
sum+=(x-fi[len-1]+1)*len;
return sum;
}
int main(){
fi[0]=1;
for(int i=1;i<=15;i++)
fi[i]=fi[i-1]*10;
int q;
cin>>q;
while(q--){
scanf("%lld",&k);
//问题1
LL l=1,r=INF;
LL ans;
while(l<=r){
LL mid=(l+r)>>1;
LL x=check(mid);
if(x<k)
l=mid+1;
else {
ans=mid;
r=mid-1;
}
}
//问题2
k-=check(ans-1);
l=1,r=ans;
while(l<=r){
LL mid=(l+r)>>1;
LL x=check2(mid);
if(x<k)
l=mid+1;
else {
ans=mid;
r=mid-1;
}
}
k-=check2(ans-1);
char ch[39];
sprintf(ch+1,"%lld",ans);
printf("%c\n",ch[k]);
}
return 0;
}
F:DP太难了。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=2e5+5;
char a[N];
multiset<LL>val,mu;
vector<LL>del[N];
LL dp[N];
int main(){
int n,k;
cin>>n>>k;
scanf("%s",a+1);
dp[n+1]=0;
mu.insert(0);
for(int i=n;i>=1;i--) {
if(i+k+2<=n+1) //删除无用的
mu.erase(mu.find(dp[i+k+2]));
for(auto it:del[i])
val.erase(val.find(it));
dp[i]=dp[i+1]+i;
if(!val.empty())
dp[i]=min(dp[i],*val.begin());
if(a[i]=='1'){
LL x=*mu.begin()+i;
dp[i]=min(dp[i],x);
val.insert(x);
if(i-k-1>=1)
del[i-k-1].push_back(x);
}
mu.insert(dp[i]);
}
printf("%lld\n",dp[1]);
return 0;
}