A. Vova and Train
C++代码如下:
#include<iostream>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int L,v,l,r;
cin>>L>>v>>l>>r;
cout<<L/v-(r/v-(l-1)/v)<<endl;
}
return 0;
}
B. Heaters
题意:简化版:给定一些区间,问最少需要几个区间才能覆盖数组中的所有点
步骤:
1、对所有区间进行按左端点从小到大的排序,last表示上一次遍历的区间的最右端点,初始化为0
2、遍历区间,对所有区间左端点小于等于last+1的的区间,找出它们中右端点最大的一个,选择右端点最大的一个区间,更新last为这个最大的右端点
3、若找不到右端点最大的区间或者找到的最大的右端点都等于last,则退出循环
4、重复步骤2,直到last==n为止
最后,如果last!=n,输出-1,否则输出区间的个数ans
C++代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
typedef pair<int,int> PII;
PII s[N];
int a[N],cnt;
int main(){
int n,r;
cin>>n>>r;
for(int i=1;i<=n;i++)cin>>a[i];
int sum=0,ans=0;
for(int i=1;i<=n;i++){
if(a[i]==1){
//所有区间都涵盖在1~n当中
int L=max(i-r+1,1),R=min(i+r-1,n);
s[cnt++]={L,R};
sum++;
}
}
sort(s,s+cnt);
int last=0,j=0;
while(last<n){
int t=last;//t存储要找的最大的右端点
while(j<cnt&&s[j].first<=last+1){
t=max(t,s[j].second);
j++;
}
if(t>last)last=t,ans++;//选择右端点最大的一个区间,ans++,last=t
else break;
}
if(last!=n)cout<<-1<<endl;
else cout<<ans<<endl;
return 0;
}
C. Books Queries
题意:(简化版)往书架上放书,从中间开始放每次要么放在左边,要么放在右边(假设书架无限长),对于每次询问,L和R表示放书,?表示询问,问的是最少取下几本书才能让这本书在边缘,即问该书左边和右边的书的最小数min(左边书的数量,右边书的数量)
步骤:
1、设置一个长度为书架两倍的数组,2*N,从中间开始放书,hh=N,tt=N+1,放书时hh往左减,tt往右加,数组a[N]记录每本书放在书架上的位置
2、对于每次?询问图书b,输出min(a[b]-hh-1,tt-a[b]-1)即可
C++代码如下:
#include<iostream>
using namespace std;
const int N=200010;
int q[2*N],a[N];
int hh=N,tt=N+1;
int n;
int main(){
cin>>n;
for(int i=0;i<n;i++){
char c;
int b;
cin>>c>>b;
if(c=='L')q[hh--]=b,a[b]=hh+1;
else if(c=='R')q[tt++]=b,a[b]=tt-1;
else cout<<min(a[b]-hh-1,tt-a[b]-1)<<endl;
}
return 0;
}
D. Boxes Packing
题意:将物品放入盒子中,盒子的数量有限,所有盒子只能放编号连续的物品,问最多可以放下几个物品,很明显的二分
注意以下几点:
- 如果当前方案合适,则从mid到n的所有物品都必须放得下
- 如果遇到了一个物品大于盒子容量,直接返回false,不用看后面的,因为一定会导致放的物品不连续
- 遍历物品时盒子不够了也返回false
C++代码如下:
#include<iostream>
using namespace std;
const int N=200010;
int a[N];
int n,m,k;
bool check(int mid){
int cnt=1,remain=k,flag=0;
for(int i=mid;i<=n;i++){
if(a[i]<=remain)remain-=a[i];
else{
cnt++;
remain=k;
//如果当前物品大于盒子容量或者盒子不够了,返回false
if(a[i]>k||cnt>m)return false;
i--;
}
}
return true;
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++)cin>>a[i];
int l=0,r=n;
while(l<r){
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
if(l==n&&a[n]>k)cout<<0<<endl;
else cout<<n-l+(l!=0)<<endl;
return 0;
}
E. Binary Numbers AND Sum
步骤:用字符串存储a和b,ans存储答案
1、从前往后用前缀和处理b中出现的1的个数,cnt[i]=cnt[i-1]+(b[i]=='1')
2、从后往前用i枚举a的每一位,每次遇到‘1’(假设编号为i)就找该编号前面b中出现的1的个数,出现几个1就给ans加上几个当前位在a中的二进制权值,即2^(n-i-1)
3、枚举到n-i>m,则直接跳出循环
- 计算的时候用快速幂,能降低时间复杂度
C++代码如下:
#include<iostream>
using namespace std;
const int N=200010,mod=998244353;
typedef long long LL;
int cnt[N];
int n,m,ans=0;
int qmi(int a,int k,int p){//快速幂求a^p%k的值
int res=1;
while(k){
if(k&1)res=(LL)res*a%mod;
a=(LL)a*a%mod;
k>>=1;
}
return res;
}
int main(){
cin>>n>>m;
string a,b;
cin>>a>>b;
for(int i=0;i<m;i++){
if(i==0)cnt[i]=(b[i]=='1');
else cnt[i]=cnt[i-1]+(b[i]=='1');
}
for(int i=n-1;i>=0;i--){
if(n-i<=m){
if(a[i]=='1'){
ans=(LL)(ans+(LL)cnt[m-(n-i)]*qmi(2,n-i-1,mod)%mod)%mod;
}
}else break;
}
cout<<ans<<endl;
return 0;
}
F. Yet another 2D Walking
还没写,最后一题也不一定会写,写了再更新hh