牛客小白月赛86
https://ac.nowcoder.com/acm/contest/73450#question
A
注意一下数据类型就行
#include <iostream>
using namespace std;
int main()
{
int T;
cin>>T;
while(T--)
{
int a ,b ,c,d;
cin>>a>>b>>c>>d;
a*d > c*b?cout<<"S"<<endl:cout<<"Y"<<endl;
}
}
B
分类讨论
笔记: find()没找到返回-1
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
while(n--)
{
string a, b;
cin>>a>>b;
if(a == b)puts("10");
else
{
int ok = 1;
for(auto c:a)
{
if(b.find(c) == -1)ok = 0;
}
if(ok)puts("10");
else puts("0");
}
}
return 0;
}
C
如果暴力处理询问会超时
本题考点是前缀和
很重要的性质是a[i]和a[i-1]不同的话,就会分段
把从1 到 n 的段数前缀和,最后询问[l,r] 相当于询问 sum[r] - sum[l] +1
举个例子
6 1
2 2 3 1 3 3
1 3
sum[r] == sum[3] ==2 {2,2}{3}
sum[l] == sum[1] ==1 {2}
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N],sum[N],n,m;
int main()
{
scanf("%d %d",&n,&m);
for(int i = 1 ;i <= n; i++)scanf("%d",&a[i]);
for(int i = 1 ;i <= n; i++)sum[i] = sum[i-1] + (a[i]!=a[i-1]);
while(m --)
{
int l ,r;
scanf("%d %d",&l,&r);
cout<<sum[r] - sum[l] + 1 <<endl;
}
return 0;
}
D
暂时跳过,作者还没学dfs,过年事情多,学完来补
也可以评论提醒一下~~
E
题意是在一个数组中找一个子串,在满足子串的w之和(饱腹值)至少是W的情况下,使得这个子串的d之和(可口值)最大
我们从前缀和入手
求和,可能会爆int,别问,问就是int一个测试点不对
不妨让区间是 [ L , R ]
枚举 起点 L
对于每一个起点 , 找到 最小的R ,让区间[L , R] 的w之和大于等于W
方法就是对w求前缀和 ,lower_bound出 r0
二分的性质是大于等于sumw[R] >=W+sumw[L-1]
对于 [ r0 , n ],都满足w之和大于等于W
接下来是寻找d之和最大
d的表达式是sumd[R] - sumd[L-1]
即寻找 [ r0 , n ]区间里sumdR最大值,重新维护一个maxd数组,maxd[i] 表示 i-n区间sumdR的最大值
把maxd[r0] - sumd[L - 1]作为L为起点的结果,枚举所有起点,维护ans
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
long long sumw[N],sumd[N],maxd[N];
int n , W;
int main()
{
scanf("%d %d",&n, &W);
for(int i = 1;i <= n; i++)
{
scanf("%lld", &sumw[i]);
sumw[i] = sumw[i - 1] + sumw[i];
}
for(int i = 1;i <= n; i++)
{
scanf("%lld",&sumd[i]);
sumd[i] = sumd[i - 1] + sumd[i];
}
maxd[n+1] = -1e15;
for(int i = n;i >= 1;i--)
{
maxd[i] = max(maxd[i+1],sumd[i]);
}
long long ans = -1e15;
for(int L = 1 ;L <= n; L ++)
{
int R = lower_bound(sumw + L,sumw + n + 1,sumw[L-1]+W) - sumw;
ans = max(ans,maxd[R] - sumd[L-1]);
}
printf("%lld",ans);
}
最开始我没有用maxd,直接在sumd上求后缀的最大值了,导致最后sumd[L-1]数据不是原来的sumd[L-1]
F
看到等差数列,就想到用差分来做,然后暴力搜1结果TLE了,正解是set维护每一段今天补个题解,最难的就是work函数
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL N = 2e5+10;
LL a[N] , ans;
set<pair<int,int>> S;
int n, m;
void del(LL l,LL r)
{
S.erase({l,r});
ans -= (r - l + 1)*(r - l + 1);
}
void add(LL l,LL r)
{
S.insert({l,r});
ans += (r - l + 1)*(r - l + 1);
}
void inse(LL a[],LL l,LL r,LL c)
{
a[l] += c;
a[r + 1] -= c;
}
void work(int pos,LL c)
{
if(pos==1 || pos==n+1)return ;
a[pos]+=c;
if(a[pos]==1)
{
// ( 1 ) -> ( )x( )
// ( 1)( ) -> ( )(x)( )
auto [l, r] = *S.lower_bound({pos,-1});
auto [l1,_] = *prev(S.lower_bound({pos,-1}));
del(l, r);
del(l1,pos - 1);
add(l1,r);
}
else if(a[pos]-c==1)
{
//( )(x)( ) -> ( )
//( )(x ) -> ( )
//( )(x) ->( )
auto [l,r] = *prev(S.lower_bound({pos,-1}));
del(l ,r);
add(l ,pos - 1);
add(pos, r);
}
}
int main()
{
cin.tie(0);
cout.tie(0);
cin>> n >> m;
int x;
for(int i = 1; i <= n; i++)
{
cin>>x;
inse(a , i , i , x);
}
for(int i = 1; i<= n; i++)
{
int j = i + 1;
while(a[j]==1 && j <= n)j++;
j--;
add(i,j);
i = j;
}
LL c;
int l ,r;
while(m --)
{
cin>>l>>r>>c;
if(c)
{
work(l,c);
work(r+1,-c);
}
printf("%lld\n",ans);
}
return 0;
}