Acwing蓝桥杯集训·题解week4
AcWing 5589. 哞语言逻辑
大模拟,思路简单,但是实现时要注意代码写的不要混乱,严格执行思路
and优先级高于or,所以可以讲连着的and分成一块,然后统计0,1的数量前缀和,减少时间复杂度
更多细节:视频题解
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m;
//q表示用0 1 数字表示true and (为1),false or(为0),因为奇偶关系,所以相互独立
//id表示现在是第几段,l,r表示每一段的左右边界,cnt表示现在所处的段
int q[N],id[N],l[N],r[N],cnt;
int ones[N];//ones[cnt]表示前cnt段有多少个1(前缀和表示)
int zeroes[N];//表示每一段内到他的左边界有多少个0
int main(){
char str[10];
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",str);
//strcmp相等的话返回的值是0,非0表示正确
if(!strcmp(str,"true")||!strcmp(str,"or"))q[i]=1;
//i为奇数,就是一个关键词
if(i&1){
//为第一个数或者前一个为or,即表示and段的开头
if(i==1||q[i-1]){
cnt++;//段数加1
l[cnt]=i;//这段左边界为i;
r[cnt-1]=i-2;//前一段右边界为i-2
//段落数大于2,就可以开始维护ones了,cnt-1表示为cnt-2段+是否为1
//第cnt-1段的最后一个数(即i-2)就表示这一段有多少0,有0为0,没0为1,故取反
if(cnt>=2)ones[cnt-1]=ones[cnt-2]+!zeroes[i-2];
//当前数为1表示没有0
zeroes[i]=!q[i];
}
else//表示段内的前缀和
zeroes[i]=zeroes[i-2]+!q[i];//隔一个为布尔值
id[i]=cnt;//表示当前值在第cnt段内
}
}
//终点的前缀和为n
r[cnt]=n;
//维护一下最后一个段,也是看最后一个数
ones[cnt]=ones[cnt-1]+!zeroes[n];
while(m--){
int left,right;
scanf("%d%d%s",&left,&right,str);
//是为1,不是为0
bool res=!strcmp(str,"true");
//看左右分别插在了哪一个段内
int lid=id[left],rid=id[right];
//看与插入部分不相关的部分,是1还是0,分左右两个部分
int a=ones[lid-1]+ones[cnt]-ones[rid];
int b=zeroes[r[rid]]-zeroes[right];
if(l[lid]!=left)b+=zeroes[left-2];
if(res==(a||!b&&true)||res==(a||!b&&false))printf("Y");
else printf("N");
}
return 0;
}
AcWing 5590. 沿栅栏散步
乍看有点复杂,但其实适当转化后,思路就很简单,最终的路径会形成一个环,我们任意选择一个起点,沿着形成的路径,记录到达每一步所需的步数.
用二维数组记录每一个坐标对应从起点到该点的步数,由于是环,最后比较,从那一边过来所需的步数最小
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> pii;
const int maxn=2e5+10;
const int maxm=1e3+10;
int s[maxm][maxm];
pii q[maxn];
int n,m;
int get(int x,int tx){
if(tx>x)
return 1;
if(tx<x)
return -1;
return 0;
}
void solve(){
cin>>m>>n;
for(int i=1;i<=n;++i)
cin>>q[i].x>>q[i].y;
int sum=0,x=q[n].x,y=q[n].y;
for(int i=1;i<=n;++i){
int tx=q[i].x,ty=q[i].y;
int vx=get(x,tx),vy=get(y,ty);
while(x!=tx || y!=ty){
x+=vx,y+=vy;
s[x][y]=++sum;
}
}
while(m--){
pii a,b;
cin>>a.x>>a.y>>b.x>>b.y;
int dis=s[b.x][b.y]-s[a.x][a.y];
if(dis<0){
dis+=sum;
}
cout<<min(dis,sum-dis)<<endl;
}return ;
}
int main(){
int t=1;
while(t--){
solve();
}
return 0;
}
AcWing 4888. 领导者
分类讨论
其实也就2种情况
对于一个品种的牛要想成为领导者
- 它包含的另一个品种的牛是领导者,当且仅当这个牛满足另一个品种的牛包含其同品种所有牛
- 该牛包含其品种的所有牛,另一个品种的牛也包含其全部同品种牛
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
const int maxn=1e5+10;
int e[maxn];
int rh=0,rg=0;
int lh,lg;
int sh[maxn],sg[maxn];
int ysh=-1,ysg=-1;
int main(){
cin>>n>>s;s=" "+s;
for(int i=1;i<=n;++i) cin>>e[i];
for(int i=1;i<=n;++i){//找出最右边的牛
if(s[i]=='H') rh=i;
if(s[i]=='G') rg=i;
}
for(int i=1;i<=n;++i) //检查最左边的牛是否包括所有同品种的牛
if(s[i]=='H' ) {
lh=i;
if(e[i]>=rh) ysh=i;//当前i是包括所有同品种的牛
break;
}
for(int i=1;i<=n;++i){
if(s[i]=='G' ) {
lg=i;
if(e[i]>=rg) ysg=i;
break;
}
}
int ans=0;
for(int i=1;i<=n;++i){//条件啊
if(s[i]=='H')
if((ysg>i && e[i]>=ysg ) || (i==lh && rh<=e[i] && ysg>i)) ++ans;
if(s[i]=='G')
if((ysh>i && e[i]>=ysh ) || (i==lg && rg<=e[i] && ysh>i)) ++ans;
}
cout<<ans<<endl;
return 0;
}
https://www.acwing.com/problem/content/4892/
解法有点花里胡哨,二进制枚举+差分
鉴于范围很小,m台空调就用长度为m的二进制数表示,第i个位置有1,就代表第i个空调打开,所以总的有\(2^m\)个方案,从0枚举到\(2^m-1\)
因为降温都相同,所以可以用差分处理,最后从头开始累加,检验每个位置是否满足要求
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=22;
int stdtem[110];
struct node1{
int a,b,p,m;
}kt[maxn];
int quick_pow(int a,int b){
int ans=1;
while(b){
if(b&1) ans*=a;
a*=a;
b>>=1;
}return ans;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;++i){
int l,r,c;cin>>l>>r>>c;
for(int i=l;i<=r;++i) stdtem[i]=max(stdtem[i],c);
}
for(int i=0;i<m;++i)
cin>>kt[i].a>>kt[i].b>>kt[i].p>>kt[i].m;
int tot=quick_pow(2,m);
int ans=1e9+10;
for(int i=1;i<tot;++i){
int tem[110],cnt=0;
memset(tem,0,sizeof(tem));
bitset<20>binary(i);
for(int j=0;j<m;++j){
if(binary[j]){
tem[kt[j].a]+=kt[j].p;
tem[kt[j].b+1]-=kt[j].p;
cnt+=kt[j].m;
}
}
int now=0;
bool book=0;
for(int i=1;i<=100;++i){
now+=tem[i];
if(now<stdtem[i]){
book=1;
break;
}
}
if(!book) ans=min(ans,cnt);
}
cout<<ans<<endl;
}
AcWing 4905. 面包店
很有意思,遇到过好几次,不等式求交集
同时你会发现一点,时间越少,一定越能满足客人要求
但是这里有个问题在于有两个变量.
这个时候二分就能妙用,二分减少的总时间z,设减少其中一种制备饼干的时间为x,则另一种减少制备饼干的时间为z-x,解不等式,去检验制备饼干的时间x是否存在,存在则说明z比较还能减小
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t;
const int maxn=110;
int n;
int x,y;
struct node{
ll a,b,c;
}e[maxn];
bool check(ll mid){
ll minn=max(0ll,1+mid-y),maxx=min(mid,x-1ll);
for(int i=1;i<=n;++i){
long double l=e[i].b-e[i].a;
long double r=e[i].c-(long double)e[i].a*x-(long double)e[i].b*(y-mid);
if(l==0 && r<0) return false;
else if(l>0) maxx=min(maxx,(ll)floor(r/l));
else if(l<0) minn=max(minn,(ll)ceil(r/l));
}
return minn<=maxx;
}
void solve(){
cin>>n>>x>>y;
for(int i=1;i<=n;++i) cin>>e[i].a>>e[i].b>>e[i].c;
ll l=0,r=x+y-2;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
cout<<l<<endl;
return ;
}
int main(){
cin>>t;
while(t--){
solve();
}return 0;
}

浙公网安备 33010602011771号