2022牛客寒假算法基础集训营4 个人题解
2022牛客寒假算法基础集训营4 个人题解
比赛链接:2022牛客寒假算法基础集训营4
A题 R
题目大意:
小红拿到了一个长度为 \(n\) 的字符串,该字符串仅由大写字母组成。
小红很喜欢红色(用\(R\)字母表示),但她非常讨厌紫色(用\(P\)字母表示)。
她想取一个连续子串,该子串包含至少 \(k\) 个\(R\)字符,且不能包含\(P\)字符。
你能告诉她有多少合法的方案可以取到吗?
注:只要连续子串的起始位置或终止位置不同,我们就认为是两个不同的方案。
思路解析:
双指针
AC代码:
#include <algorithm>
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
char s[maxn];
int sum[maxn];
int a[maxn];
int main(){
IOS
int n,k;
cin>>n>>k;
cin>>s+1;
int top=n+1;
for(int i=1;i<=n;i++){
if(s[i]=='P')sum[i]=sum[i-1]+1;
else sum[i]=sum[i-1];
int now=n-i+1;
if(s[now]!='P')a[now]=top;
else top=now;
}
int tp=1,sum=0;
ll ans=0;
for(int i=1;i<=n;i++){
if(s[i]=='P'){
sum=0;
tp=i+1;
}
if(s[i]=='R'){
sum++;
while(sum>=k&&tp<i+1){
ans+=abs(i-a[i]);
sum-=(s[tp]==s[i]);
tp++;
}
}
}
while(tp<n+1){
tp++;
if(s[tp]=='R')tp+=1,sum-=1;
if(sum>=k)ans+=1;
}
cout<<ans<<endl;
}
B题 进制
题目大意:链接:https://ac.nowcoder.com/acm/contest/23479/B
来源:牛客网
小红拿到了一个长度为 \(n\) 的数字串 \(s\)(只有 \('0' ~ '9'\) 这十种字符),她有 \(q\) 次以下两种操作:
第一种: 输入\(1 x y\),修改第 \(x\) 个字符为 \(y\) ,即令\(s_x=y\)
第二种: 输出 \(2 x y\) ,代表查询区间 \([x,y]\),该区间子串所能表示的某进制的最小值(进制必须合法,且必须是二进制到十进制之间,可以包含前导零),对 \(1000000007\) 取模。
思路解析:
十颗线段树,对每一种进制建树维护
(贴一份队友聚聚的代码)AC代码:
#include <bits/stdc++.h>
#define debug(x) cout << #x << "=" << x << '\n';
#define ls u << 1
#define rs u << 1 | 1
#define ll long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10, mod = 1000000007;
int n, q;
char s[N];
ll qmi(ll a, ll b) {
if (!a) return 0;
ll res = 1;
while(b) {
if(b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res % mod;
}
struct segment_tree {
struct node {
int l, r;
int v, maxv;
ll val;
int len, jz;
} tr[N * 4];
void pushup(node &u, node &l, node &r) {
int t = l.jz;
u.jz = l.jz;
u.len = l.len + r.len;
u.maxv = max(l.maxv, r.maxv);
u.val = (l.val * qmi(t, r.len) % mod + r.val) % mod;
}
void pushup(int u) { pushup(tr[u], tr[ls], tr[rs]); }
void build(int u, int l, int r, int k) {
if(l == r)
tr[u] = {l, r, s[l] - '0', s[l] - '0', s[l] - '0', 1, k};
else {
tr[u] = {l, r};
int mid = l + r >> 1;
build(ls, l, mid, k), build(rs, mid + 1, r, k);
pushup(u);
}
}
void modify(int u, int x, int v) {
if(tr[u].l == x && tr[u].r == x) {
int k = tr[u].jz;
tr[u] = {x, x, v, v, v, 1, k};
} else {
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid)
modify(ls, x, v);
else
modify(rs, x, v);
pushup(u);
}
}
node query(int u, int l, int r) {
if(tr[u].l >= l && tr[u].r <= r) return tr[u];
int mid = tr[u].l + tr[u].r >> 1;
if(r <= mid) return query(ls, l, r);
if(l > mid) return query(rs, l, r);
node res, left = query(ls, l, r), right = query(rs, l, r);
pushup(res, left, right);
return res;
}
} tree[11];
void solve() {
cin >> n >> q;
cin >> (s + 1);
for(int i = 2; i <= 10; i++) { tree[i].build(1, 1, n, i); }
while(q--) {
int op, x, y;
cin >> op >> x >> y;
if(op == 1) {
for(int i = 2; i <= 10; i++) tree[i].modify(1, x, y);
} else {
auto tmp = tree[2].query(1, x, y);
int mx = tmp.maxv;
cout << tree[mx + 1].query(1, x, y).val << '\n';
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
// int T;cin>>T;while(T--)
solve();
}
C题 蓝彗星
题目大意:
给出 \(n\) 颗彗星以及他们的颜色,蓝或者红,持续时间和开始时间,问有多少秒只能看到蓝彗星看不到红彗星
思路解析:
蓝红分别差分即可
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
int a[maxn];
char col[maxn];
int b[maxn],r[maxn];
int main(){
IOS
int n,t;
cin>>n>>t;
cin>>col+1;
for(int i=1;i<=n;i++){
cin>>a[i];
if(col[i]=='B')b[a[i]]++,b[a[i]+t]--;
else r[a[i]]++,r[a[i]+t]--;
}
int x=0,y=0;
ll ans=0;
for(int i=1;i<=200005;i++){
x+=b[i];
y+=r[i];
if(x&&y==0)ans++;
}
cout<<ans<<endl;
}
D题 雪色光晕
题目大意:
二维坐标中,给出小红和小果的坐标,每一秒给出一个方向向量,并且小红按照它移动,问在移动过程中,两个人的最短距离是多少
思路解析:
基础二维几何,点到线段的距离
AC代码:
//代码太长我就不放了hh
E题 真假签到题
题目大意:
给出以下代码:
long long f(long long x){
if(x==1)return 1;
return f(x/2)+f(x/2+x%2);
}
给出\(x\),求\(f(x)\)
思路解析:
通过观察,我们发现\(f(x)=x\),输出\(x\)即可
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
long long f(long long x){
if(x==1)return 1;
return f(x/2)+f(x/2+x%2);
}
int main(){
IOS
ll n;
cin>>n;
cout<<n<<endl;
}
F题 小红的记谱法
题目大意:
给出两种记谱方式,给出第二种,写出其对应的第二种(是不是觉得小飞龙没有讲清楚题意?主要是题面太长难解释自行观看hh)
思路解析:
计数,模拟即可
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
map<char ,int>q;
int main(){
IOS
string s;
cin>>s;
int x=0,y=0;
q['C']=1;
q['D']=2;
q['E']=3;
q['F']=4;
q['G']=5;
q['A']=6;
q['B']=7;
for(int i=0;i<s.size();i++){
if(s[i]=='<')x++;
else if(s[i]=='>')y++;
else {
int now=q[s[i]];
cout<<now;
if(x>y){
for(int i=y;i<x;i++)cout<<".";
}
else if(y>x)for(int i=x;i<y;i++)cout<<"*";
}
}
}
G题 子序列权值乘积
题目大意:
求出数组中非空子序列的权值的乘积是多少
权值定义为:\(最大值*最小值\)
思路解析:
我们发现序列顺序对于序列的权值是没有影响的,我们可以先排序与,枚举每个值作为所选序列的最大值/最小值,分别计算其对于答案的贡献。
作为最小值的贡献:\(a[i]^{2^{i-1}}\)
作为最大值的贡献:\(a[i]^{2^{n-i}}\)
由于指数较大,所以使用欧拉降幂
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
const int mod=1e9+7;
ll a[maxn];
ll ans=1;
ll ksm(ll a,ll b,ll mod){
ll ans=1,base=a%mod;
while(b){
if(b&1)
ans=ans*base%mod;
base=base*base%mod;
b>>=1;
}
return ans%mod;
}
ll oljm(ll m,ll k,ll n){
if(m%mod==0)return 0;
ll p=ksm(k,n,mod-1);
return ksm(m,p,mod)%mod;
}
int main(){
IOS
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
ans*=oljm(a[i],2,i-1);
ans%=mod;
ans*=oljm(a[i],2,n-i);
ans%=mod;
}
cout<<ans%mod<<endl;
}
H题 真真真真真签到题
题目大意:
小红和紫被困在一个正方体的内部。紫先选择了一个位置,然后小红选择一个位置。紫希望离小红尽可能近,小红希望离紫尽可能远。两人都会选择最优策略。
已知她们最终的距离为 \(x\) 。小红想知道正方体的体积是多少?
思路解析:
因为紫先选,所以他会选择正方体的中心来保证最优,然后小红要离中点尽量远,所以选择正方体的顶点
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
int main(){
double x;
cin>>x;
x=x*2/sqrt(3);
printf("%0.6f",x*x*x);
}
I题 爆炸的符卡洋洋洒洒
题目大意:
小红有\(n\)张卡,每张卡消耗为\(a_i\),威力为\(b_i\),问能选择最大的威力和是多少
特别的,必须保证所选卡的消耗和为\(k\)的倍数
思路解析:
\(01\)背包的变形版本
我们只需要把转移改为\(f[i][j]=max(f[i][j],f[i-1][(j-v[i]+m)\%m]+w[i])\)
特别的我们需要判断是否有方案可以转移才能够向下转移
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1005;
ll f[maxn][maxn];
ll v[maxn], w[maxn];
int n, m;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> v[i] >> w[i];
v[i]%=m;
f[i][v[i]]=w[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m; j++) {
f[i][j] = max(f[i][j],f[i-1][j]);
if(f[i - 1][(j - v[i]+m)%m])
f[i][j] = max(f[i][j], f[i - 1][(j - v[i]+m)%m] + w[i]);
}
}
if(f[n][0]==0)cout<<-1<<endl;
else cout<<f[n][0]<<endl;
}
J题 区间合数的最小公倍数
题目大意:
求 \([l,r]\) 区间所有合数的最小公倍数是多少
思路解析:
将区间内每个数分解质因数,那么每一个质因子取最大值即为乘积的质因子,然后计算即可
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
const int mod=1e9+7;
int st[maxn],prime[maxn],tot;
ll ksm(ll a,ll b){
ll ans=1,base=a%mod;
while(b){
if(b&1)
ans=ans*base%mod;
base=base*base%mod;
b>>=1;
}
return ans;
}
void get_primes(int n){
for(int i=2;i<=n;i++){
if(!st[i])prime[++tot]=i;
for(int j=1;prime[j]<=n/i;j++){
st[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
int p[maxn];
void divide(int x)
{
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
int s = 0;
while (x % i == 0) x /= i, s ++ ;
p[i]=max(p[i],s);
//cout << i << ' ' << s << endl;
}
if (x > 1) p[x]=max(p[x],1);
}
int main(){
IOS
get_primes(30505);
int l,r;
cin>>l>>r;
if(l==1)l++;
ll ans=1;
int sum=0;
for(int i=l;i<=r;i++){
if(st[i]){
divide(i);
sum++;
}
}
if(sum==0)cout<<-1<<endl;
else {
for(int i=1;i<=tot;i++){
ans*=ksm(prime[i],p[prime[i]])%mod;
ans%=mod;
}
cout<<ans<<endl;
}
}
K题 小红的真真假假签到题题
题目大意:
小红拿到了一个正整数 \(x\) 。她想构造一个正整数 \(y\),满足以下性质:
- \(y\) 是 \(x\) 的倍数,且 \(x\) 和 \(y\) 不能相等。
- \(x\) 在二进制表示下(为一个\(01\)串)是 \(y\) 的二进制表示的一个子串。且 \(x\) 和 \(y\) 的二进制表示的\(1\)的个数不能相同。
- \(y\) 必须为不超过 \(10^{19}\)的正整数。
思路解析:
很多种构造方式,小飞龙的方法:
\(110 -> 110110\)
\(1011 -> 10111011\)
\(10 -> 1010\)
这样的方式扩大
AC代码:
#include<bits/stdc++.h>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define endl '\n'
#define pii pair<int,int>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int maxn=1e6+5;
int main(){
IOS
ll x;
cin>>x;
ll op=x;
ll now=x;
int sum=0;
while(now){
now/=2;
sum++;
}
x<<=sum;
x+=op;
cout<<x<<endl;
}
L题 在这冷漠的世界里光光哭哭
题目大意:
思路解析:
AC代码:
https://files.cnblogs.com/files/blogs/696109/tt.rar?t=1691327061&download=true
推广一波小飞龙博客:戳这里@不会飞的小飞龙
本文来自博客园,作者:不会飞的小飞龙,转载请注明原文链接:https://www.cnblogs.com/xiaofeilong7816/p/15838958.html