E. Decode
题目
为了获得你最爱的女主角,你不惜黑进了游戏的源代码。经过数天的努力,你终于找到了编码游戏中 gacha 系统的二进制字符串。为了解码它,您必须首先解决以下问题。
给你一个长度为 𝑛n 的二进制字符串 𝑠s 。对于每一对整数 (𝑙,𝑟)(l,r) (1≤𝑙≤𝑟≤𝑛)(1≤l≤r≤n) (1≤𝑙≤𝑟≤𝑛)(1≤l≤r≤n) 的整数对,计算 (𝑥,𝑦)(x,y) (𝑙≤𝑥≤𝑦≤𝑟)(l≤x≤y≤r) 中有多少个整数对。 (𝑙≤𝑥≤𝑦≤𝑟)(l≤x≤y≤r) ,使得子串 𝑠𝑥𝑠𝑥+1...𝑠𝑦sxsx+1...sy 中 𝟶0 的数量等于 𝟷1 的数量。
输出所有可能的 (𝑙,𝑟)(l,r) modulo 109+7109+7 的计数之和。
输入
第一行包含 𝑡t ( 1≤𝑡≤10001≤t≤1000 ) - 测试用例数。
每个测试用例都包含二进制字符串 𝑠s ( 1≤|𝑠|≤2⋅1051≤|s|≤2⋅105 )。保证 𝑠s 只包含字符 𝟶0 和 𝟷1 。
保证所有测试用例中 |𝑠||s| 的总和不超过 2⋅1052⋅105 。
输出
针对每个测试用例,输出一个整数,即答案的模数 109+7109+7 。
做法
典型的区间01串预处理成-1 和 +1, 然后前缀和相等的地方就是0和1数量相等的区间。
#include<bits/stdc++.h>
using namespace std;
int t;
const long long mod=1e9+7;
string s;
long long qzh[200010];
int main(){
cin>>t;
while(t--){
cin>>s;
map<long long,long long> mp;
for(int i=0;i<s.size();i++){
if(s[i]=='1') qzh[i+1]=qzh[i]+1;
else qzh[i+1]=qzh[i]-1;
}
long long ans=0;
for(int i=0;i<=s.size();i++){//枚举右端点
ans=(ans+(s.size()-i+1)*mp[qzh[i]])%mod;
mp[qzh[i]]+=i+1;//能作为左端点的个数
mp[qzh[i]]%=mod;
}
cout<<ans<<endl;
}
}
F.
题目
Sparkle 给了你两个长度为 𝑛n 的数组 𝑎a 和 𝑏b 。最初,您的分数是 00 。在一次操作中,您可以选择一个整数 𝑖i 并将 𝑎𝑖ai 添加到您的分数中。然后,您必须设置 𝑎𝑖ai = max(0,𝑎𝑖−𝑏𝑖)max(0,ai−bi) 。
在闪亮引爆核弹之前,您只有时间进行 𝑘k 次运算!在 𝑘k 次运算后,您能获得的最高分数是多少?
输入
第一行包含 𝑡t ( 1≤𝑡≤10001≤t≤1000 ) - 测试用例数。
每个测试用例的第一行包含 𝑛n 和 𝑘k ( 1≤𝑛≤2⋅105,1≤𝑘≤1091≤n≤2⋅105,1≤k≤109 ) - 数组的长度和可执行的操作数。
下一行包含 𝑛n 个整数 𝑎1,𝑎2,...𝑎𝑛a1,a2,...an ( 1≤𝑎𝑖≤1091≤ai≤109 )。
下面一行包含 𝑛n 个整数 𝑏1,𝑏2,...𝑏𝑛b1,b2,...bn ( 1≤𝑏𝑖≤1091≤bi≤109 )。
保证所有测试用例中 𝑛n 的总和不超过 2⋅1052⋅105 。
输出
对于每个测试用例,输出一个整数,即经过 𝑘k 次操作后可以获得的最大分数。
做法
#include<bits/stdc++.h>
using namespace std;
int t;
int n,k;
long long a[200010],b[200010];
int isleft(long long x){//最后一次操作最多能获得的分数
int cnt=0;
for(int i=1;i<=n;i++){
if(a[i]<x) continue;
cnt+=(a[i]-x)/b[i]+1;//a[i]能拿的次数
if(cnt>=k) return 1;
}
return 0;
}
int main(){
cin>>t;
while(t--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
long long l=0,r=1e9+10;
while(l+1<r){
long long mid=l+(r-l)/2;
if(isleft(mid)) l=mid;
else r=mid;
}
int cnt=0;
long long sum=0;
for(int i=1;i<=n;i++){
if(a[i]<l) continue;
int t=(a[i]-l)/b[i]+1;//a[i]能拿的次数
if(a[i]-b[i]*(t-1)==l){//最后一次操作不一定要那么多x
t--;
cnt++;
}
t=min(t,k);
k-=t;
sum+=1ll*a[i]*t-1ll*t*(t-1)/2*b[i];//分数
}
sum+=min(cnt,k)*l;
cout<<sum<<endl;
}
}