只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;
}