题目讲解:牛客周赛39讲题直播回放_哔哩哔哩_bilibili
题号 | 标题 | 已通过代码 | 通过率 | 我的状态 |
---|---|---|---|---|
A | 小红不想做炸鸡块粉丝粉丝题 | 点击查看 | 1978/2610 | 未通过 |
B | 小红不想做鸽巢原理 | 点击查看 | 1172/8606 | 未通过 |
C | 小红不想做完全背包(easy) | 点击查看 | 1261/3574 | 未通过 |
D | 小红不想做完全背包 (hard) | 点击查看 | 416/5728 | 未通过 |
E | 小红不想做莫比乌斯反演杜教筛求因子和的前缀和 | 点击查看 | 557/3456 | 未通过 |
F | 小红不想做模拟题 | 点击查看 | 346/1750 | 未通过 |
G | 小红不想做平衡树 | 点击查看 | 31/3150 | 未通过 |
B.小红不想做鸽巢原理
思路:贪心,由于最后一定会剩下sum%k个球,我们想让球的颜色最少,最好的方法是让剩下的球全部是一个颜色的。所以先求一下sum%k看剩几个球,再对数组排序,倒着取看结果是否为负,若为负则表示当前颜色是不能取完的(很直觉的做法,感觉也可以从前往后进行模拟,比较符合正常思路)。
#include<bits/stdc++.h>
using namespace std;
int main(){
long long n,k,sum=0;
cin>>n>>k;
vector<long long> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
sort(a.begin()+1,a.end());
sum %= k;
long long cnt = 0;
for(int i=n;i;i--){
if(sum<=0){
cout<<cnt<<endl;
return 0;
}
sum-=a[i];
cnt++;
}
cout<<n<<endl;
return 0;
}
C&D.小红不想做完全背包
思路:dp。dp[i]表示%p后能凑出i这个数字使用最少的数字的个数。dp是考虑从哪个状态枚举到哪个状态。但好像没讲全对,可能是状态转移的更新部分不太对。本题也可以使用bfs解决,感觉很妙。
正确的dp代码:代码查看 (nowcoder.com)
以下是bfs的正确代码。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int f[2000+10],vis[2000+10];
int main()
{
int n,p;
cin>>n>>p;
ll a[n+10];
queue<pair<ll,ll>>q;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(f[a[i]%p]==0)
{
f[a[i]%p]=1;
q.push({a[i]%p,1});
vis[a[i]%p]=1;
}
}
while(q.size())
{
ll x=q.front().first,y=q.front().second;
if(x==0)
{
cout<<y<<endl;
return 0;
}
for(int i=0;i<p;i++)
{
if(f[i]==1&&vis[(i+x)%p]==0)
{
q.push({(i+x)%p,y+1});
vis[(i+x)%p]=1;
}
}
q.pop();
}
return 0;
}
E.小红不想做莫比乌斯反演杜教筛求因子和的前缀和
思路:推公式,不是很难,题目完全是在迷惑大家。
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m, p, x;
cin >> n >> m >> p >> x;
int ans = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(x-i*j<=0) continue;
int up = x-i*j,down = (2*(i+j));
if(up%down!=0) continue;
int h = up/down;
if(h<=p) ans++;
}
}
cout<<ans<<endl;
return 0;
}
F.小红不想做模拟题
思路:带懒标记的线段树。
#include<bits/stdc++.h>
#define lc u<<1
#define rc u<<1|1
using namespace std;
int n,q,a[101010],b[101010];
struct node{
int l,r,c1,c2,c;
int lz1,lz2;
}tr[404040];
void push_up(int u){
tr[u].c1 = tr[lc].c1+tr[rc].c1;
tr[u].c2 = tr[lc].c2+tr[rc].c2;
tr[u].c = tr[lc].c+tr[rc].c;
}
void build(int u,int l,int r){
tr[u] = {l,r,a[l],b[l],a[l]&b[l]};
if(l==r) return;
int mid = l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(u);
}
void push_down(int u){
if(tr[u].lz1){
int lz = tr[u].lz1;
tr[lc].c1 = tr[lc].r - tr[lc].l + 1;
tr[lc].c = tr[lc].c2;
tr[rc].c1 = tr[rc].r - tr[rc].l + 1;
tr[rc].c = tr[rc].c2;
tr[rc].lz1 = 1;
tr[lc].lz1 = 1;
tr[u].lz1 = 0;
}
if(tr[u].lz2){
int lz = tr[u].lz2;
tr[lc].c2 = tr[lc].r - tr[lc].l + 1;
tr[lc].c = tr[lc].c1;
tr[rc].c2 = tr[rc].r - tr[rc].l + 1;
tr[rc].c = tr[rc].c1;
tr[rc].lz2 = 1;
tr[lc].lz2 = 1;
tr[u].lz2 = 0;
}
}
void modify(int u,int l,int r,int op){
if(l<=tr[u].l&&tr[u].r<=r){
if(op==1){
tr[u].c1 = tr[u].r - tr[u].l +1;
tr[u].c = tr[u].c2;
tr[u].lz1 = 1;
}else{
tr[u].c2 = tr[u].r - tr[u].l +1;
tr[u].c = tr[u].c1;
tr[u].lz2 = 1;
}
return;
}
push_down(u);
int mid = tr[u].l+tr[u].r>>1;
if(l<=mid) modify(lc,l,r,op);
if(r>mid) modify(rc, l, r, op);
push_up(u);
}
int main(){
string A,B;
cin>>n>>A>>B>>q;
int ans = 0;
for(int i=0;i<n;i++){
a[i+1] = A[i] - '0';
b[i+1] = B[i] - '0';
}
build(1,1,n);
while(q--){
char op;
int l,r;
cin>>op>>l>>r;
int x = op-'A'+1;
modify(1, l, r, x);
cout<<tr[1].c<<endl;
}
return 0;
}