2021-06 个人复习用题
六月份期末考试,攒了一些题目理了一下(有的题目可能忘掉了),补一下这部分题目的题解。
这道题是树状数组的模板题,但是可能因为太久没写了没想到
经典的用树状数组维护区间内合法数个数,不多解释。
#include<bits/stdc++.h>
using namespace std;
int n1,n2,n;
int a[100005],que[100005],treea[100005];
long long ans;
int x;
bool cmp(int x,int y){
return a[x]>a[y];
}
void add(int t,int x){
while(t<=n){
treea[t]+=x;
t+=t&-t;
}
}
int query(int x){
int res=0;
for(int i=x;i>0;i-=i&-i){
res+=treea[i];
}
return res;
}
int main(){
cin>>n1>>n2;
n=n1+n2;
for(int i=n1;i>0;i--){
cin>>a[i];
que[i]=i;
add(i,1);
}
for(int i=n1+1;i<=n;i++){
cin>>a[i];
que[i]=i;
add(i,1);
}
sort(que+1,que+1+n,cmp);
x=n1;
for(int i=1;i<=n;i++){
if(que[i]>x){
ans+=query(que[i])-query(x-1)-1;
}
else{
ans+=query(x)-query(que[i]-1)-1;
}
add(que[i],-1);
x=que[i];
}
cout<<ans;
return 0;
}
二、上海理工大学第二届“联想杯”全国程序设计邀请赛–I
题意概括:第一行输入一个n表示01字符串长度,一个k表示可以把1变成0的次数。第二行给一串长为n的01字符串。
对于每一串长为l的连续1串,会贡献(l+1)*l/2的sum值,求最终最小的sum值为多少
分析:肯定是贪心算法,不过贪心的是某个连续1序列中当他分成t次到t+1次会减少多少,这个值要用单调队列优化,代码如下。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,sum1,sum2,sum,k;
char s[100005];
struct node{
int p,d,cost;
bool operator<(const node x)const{
return cost < x.cost;
}
};
priority_queue <node> p;
node t;
int make(int q,int d){
q-=d;
d++;
int a=q/d,b=q%d;
return (a+1)*a/2*(d-b)+(a+1)*(a+2)/2*b;
}
signed main(){
cin>>n>>k;
cin>>s;
for(int i=0;i<=n;i++){
if(s[i]=='1'){
sum++;
}
else if(sum){
node a={sum,0,make(sum,0)-make(sum,1)};
p.push(a);
sum1+=(sum+1)*sum/2;
sum=0;
}
}
while(!p.empty()&&sum1>k){
sum2++;
t=p.top();
p.pop();
sum1-=t.cost;
t.d++;
t.cost=make(t.p,t.d)-make(t.p,t.d+1);
p.push(t);
}
cout<<sum2;
}
暂时先写两道,别的以后再补