只A了ABCE场后的F暴力切了,但是复杂度应该是不妥的,D和G找时间补补吧

A. 小红不想做炸鸡块粉丝粉丝题

水题

参考代码

void solve() {
    cin(a);
    ll sum=a;
    rep(i,2,6){
        cin(tmp);
        sum+=tmp;
    }
    cout<<ANS[a<1.0*sum/30];
}

B. 小红不想做鸽巢原理

贪心

大概思路

直接按数量从小到大排序,然后跑贪心,维护当前记录颜色数和当前小球数和,尽可能把数量少的颜色合并到一堆,当小球个数超过k个时,颜色计数置 0/1,小球数模k。

参考代码

void solve() {
    cin(n);cin(k);
    vector<int> a(n);
    for(auto &i:a){
        cin>>i;
        i%=k;//读入的时候就先拿一遍
    }
    sort(a.begin(),a.end());
    int cnt=0;
    int now=0;
    rep(i,0,n-1){
        now+=a[i];
        cnt+=(a[i]!=0);//颜色种类计数
        if(now>=k){//溢出的时候重置一下计数器
            now%=k;
            cnt=(now%k!=0);
        }
    }
    cout<<cnt;
}

C. 小红不想做完全背包(easy)

暴力

大概思路

易知答案的范围是1到3,取初始答案为3,然后暴力遍历可选数,当遍历到的数是k的倍数时,取答案为1,直接输出;当遍历到的数和集合中另一个数(可以是本身)相加为3的倍数时,取答案为2,继续遍历看看有没有可能使答案为1;当遍历完了都不符合时,只能输出3.

参考代码

void solve() {
    cin(n);cin(k);
    set<int>s;
    rep(i,1,n){
        cin(tmp);
        s.insert(tmp);
    }
    int ans=3;
    bool o=0;
    for(auto &i:s){
        if(i%3==0){ans=1;break;}
        if(!o)for(auto j:s){
            if((i+j)%3==0){ans=min(ans,2);o=1;break;}
        }
    }
    CA;
}

D. 小红不想做完全背包(hard)

数学,DP,最短路

大概思路

设dp[i]状态为取模后到达数字 $i$ 最少需要几步,易知 $dp[i]+1$ 可以转移到 $dp[(i+a[j])%k]$,直接枚举数组的每个元素,内层再枚举数字 $i$ 即可。

(听别人说其实是最短路问题?)

参考代码

void solve() {
    cin(n);cin(k);
    vector<ll>dp(k,k);
    vector<int>a(n);
    for(auto &i:a){cin>>i;i%=k;dp[i]=1;}
    for(auto i:a){
        auto dp_=dp;
        rep(j,0,k-1)dp[(i+j)%k]=min(dp[(i+j)%k],dp_[j]+1);
    }
    cout<<dp[0];
}

E. 小红不想做莫比乌斯反演杜教筛求因子和的前缀和

暴力

大概思路

水题,直接枚举长和宽,然后判断算出来的高是否合法即可

参考代码

void solve() {
    cin(x);cin(y);cin(z);cin(s);
    ll cnt=0;
    rep(i,1,x)rep(j,1,y){
        if(s<i*j)break;
        ll S=s-i*j;
        if(S%(2*(i+j))!=0)continue;
        ll h=S/(2*(i+j));
        if(h>=1&&h<=z)cnt++;
    }
    cout<<cnt;
}

F. 小红不想做模拟题

线段树、暴力

大概思路

暴力:

答案是单调增加的,用数据结构记录下A,B串哪些位置有被修改过,下次修改时直接遍历一遍跑一遍,更新答案即可。(55ms 题目数据感觉水了,这个方法复杂度最坏应该是 $O(n^2)$ 的)

数据结构优化:

直接开个set维护A和B串的可更新位置,然后遍历的时候用while(sa.lower_bound(l)<=r)来更新即可,这样的遍历次数是不超过2n的。(430ms 理论复杂度:$O(nlogn)$)

参考代码

//暴力
char a[100005];
char b[100005];
bool visa[100005];
bool visb[100005];

int res=0;
char tp;int l,r;

void solve(){
    cin(n);
    rep(i,1,n)cin>>a[i];
    rep(i,1,n){cin>>b[i];res+=(a[i]=='1'&&b[i]=='1');}
    cin(q);
    
    while(q--){
        cin>>tp>>l>>r;
        if(tp=='A'){
            rep(i,l,r){
                if(!visa[i]){
                    visa[i]=1;
                    if(a[i]=='0'&&b[i]=='1')res++;
                    a[i]='1';
                }else continue;
            }
        }else{
            rep(i,l,r){
                if(!visb[i]){
                    visb[i]=1;
                    if(a[i]=='1'&&b[i]=='0')res++;
                    b[i]='1';
                }else continue;
            }
        }
        cout<<res<<et;
    }
}
//数据结构优化
void solve(){
    int res=0;
    set<int>sa,sb;
    cin(n);
    scin(a);a=" "+a;
    scin(b);b=" "+b;
    
    rep(i,1,n){if(a[i]=='0')sa.insert(i);}
    rep(i,1,n){if(b[i]=='0')sb.insert(i);res+=(a[i]=='1'&&b[i]=='1');}
    cin(q);
    
    char tp;int l,r;
    while(q--){
        cin>>tp>>l>>r;
        if(tp=='A'){
            while(true){
                auto it=sa.lower_bound(l);
                if(it==sa.end()||*it>r)break;
                if(a[*it]=='0'&&b[*it]=='1')res++;
                a[*it]='1';sa.erase(*it);
            }
        }else{
            while(true){
                auto it=sb.lower_bound(l);
                if(it==sb.end()||*it>r)break;
                if(a[*it]=='1'&&b[*it]=='0')res++;
                b[*it]='1';sb.erase(*it);
            }
        }
        cout<<res<<et;
    }
}

G. 小红不想做平衡树

待补

附录

这里放上用到的文件头和main函数

#include<iostream>
#include<vector>
#include<cmath>
#include<string>
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
//不要用#define,使用using可以用ll格式转换,但是#define不行
#define et '\n'
#define reg register
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rrep(i,a,b) for(int i=(a);i>=(b);i--)
#define cin(a) ll a;cin>>a
#define dcin(a) ld a;cin>>a
#define scin(a) string a;cin>>a
#define CA cout<<ans<<et
#define CY cout<<"YES"<<et
#define CN cout<<"NO"<<et
#define max(a,b) ((a>b)?(a):(b))
#define min(a,b) ((a<b)?(a):(b))
//#define PP(l,r,CK) *ranges::partition_point(ranges::iota_view((l),(r)+1),(CK))
string ANS[2] = { "No\n","Yes\n" };
int M = 1e9 + 7;
//inline ll MO(ll x){return (x%M+M)%M;}

void solve(){

}

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    //pre();
    cin(t); while (t--)
    solve();
    return 0;
}