目录
A. Vova and Train
求区间重点额数量,由于数量具有前缀和效应所以我们考虑直接使用前缀和即可
void solve(){
cin>>L>>v>>l>>r;
int ans = L/v -(r/v-(l-1)/v);
cout << ans << endl;
return ;
}
B. Heaters
简单的线段覆盖问题,按照左端点排序,在满足可以覆盖左端点的同时选择最靠右边的线段即可(简单小贪心)
vector<PII> seg;
bool cmp(PII a,PII b){
if(a.first==b.first) return a.second>b.second;
return a.first<b.first;
}
void solve(){
cin>>n>>r;
for(int i=1;i<=n;i++){
int x; cin>>x;
if(x) seg.push_back({i-r+1,i+r-1});
}
sort(seg.begin(),seg.end(),cmp);
int ed = 0;
int ans = 0;
for(int i=0;i<seg.size();i++){
int j = i;
int last = ed;
if(seg[i].first>last+1) break;
while(j<seg.size() and seg[j].first<=last+1) ed = max(ed,seg[j].second),j++;
j--;
i=j;
ans ++ ;
if(ed>=n) break;
}
cout << (ed>=n ? ans : -1) << endl;
return ;
}
C. Books Queries
左右插数,考虑使用的对左右的数用正数和负数来区分即可,如果查询的数是左右两边注意减去0所占据的位置
int idxl,idxr;
void solve(){
cin>>n;
while(n--){
char op; int x; cin>>op>>x;
if(op=='?'){
int t = pos[x];
if(t>0) cout << min(idxr-t,t-idxl-1) << endl;
else cout << min(idxr-t-1,t-idxl) << endl;
}
else{
if(op=='L') cnt[--idxl]=x,pos[x]=idxl;
else cnt[++idxr]=x,pos[x]=idxr;
}
}
return ;
}
D. Boxes Packing
注意题目意思,其实是丢弃前缀,题目明显的具有二分性质,所以可以考虑从什么位置开始处理
,为了便于处理是否是被装在盒子里,我们可以直接用数组来表示盒子即可
int a[N],b[N];
bool check(int St){
for(int i=1;i<=m;i++) b[i]=k;
int cnt=0,j=1;
for(int i=St;i<=n;i++){
if(a[i]<=b[j]){
b[j]-=a[i];
}
else{
j++;
if(j>m) return false;
b[j]-=a[i];
}
}
return true;
}
void solve(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>a[i];
int l=1,r=n+1;
while(l<r){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<n-l+1<<endl;
return ;
}
E. Binary Numbers AND Sum
前缀和思路,对于每一次除以之后的操作其实就是整个大于等于这个位置的前缀的数和这个位置数的操作,所以可以直接对其做一个前缀和即可
int pre[N];
LL qmi(LL a,LL b,LL p){
LL res =1;
while(b){
if(b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
void solve(){
string a,b; cin>>n>>m>>a>>b;
a=' '+a,b=' '+b;
for(int i=1;i<=m;i++){
pre[i]=pre[i-1]+(b[i]-'0');
}
LL ans = 0;
for(int i=n,j=m,cnt=0;i>=1 and j>=1;i--,j--,cnt++){
if(a[i]=='1') ans +=(LL)qmi(2,cnt,mod)*pre[j]%mod;
ans %= mod;
}
cout << ans << endl;
return ;
}
F. Yet another 2D Walking
几何中的dp,我们考虑如果是在同一个大小状态之下,我们可以按照从最左下到最右上的顺序或者是反之,(中间点就在两个点的曼哈顿距离中)最后一定是在这两个位置中的一个取转移下一个位置,所以不妨直接对这两个状态来进行转移
struct code{
int x,y,S;
bool operator<(const code&t)const{
if(S!=t.S) return S<t.S;
if(x!=t.x) return x<t.x;
return y>t.y;
}
}e[N];
// 一个倒着的L的形状
int dp[N][2];
PII w[N];
int get(int i,int j){
auto [x1,y1,_]=e[i];
auto [x2,y2,__]=e[j];
return abs(x1-x2)+abs(y1-y2);
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++){
int x,y; cin>>x>>y;
e[i]={x,y,max(x,y)};
}
sort(e+1,e+1+n);
int cnt=0;
for(int i=1;i<=n;i++){
int j=i;
while(j+1<=n && e[i].S==e[j+1].S) j++;
w[++cnt]={i,j};// 表示左右边界
i=j;
}
for(int i=1;i<=cnt;i++){
auto [l,r]=w[i];
auto [ll,rr]=w[i-1];
dp[i][0]=min(dp[i-1][1]+get(rr,r),dp[i-1][0]+get(ll,r))+get(l,r);// 表示当前在左上
dp[i][1]=min(dp[i-1][1]+get(rr,l),dp[i-1][0]+get(ll,l))+get(l,r);// 表示当前在右下
}
cout<<min(dp[cnt][1],dp[cnt][0])<<endl;
return ;
}