P8593 「KDOI-02」一个弹的投 题解
其实除了提示中给的平抛运动落点公式本题和物理基本没关系
首先有一个结论,只有
那么,我们可以对每一个
求出所有导弹的威力后,就是一个非常简单的贪心题了。设导弹的威力为
#include<bits/stdc++.h>
using namespace std;
const int N=500001;
const double g=9.8;
int n,m,x,y,v,id,s,T[N],V[N],a,f[N];
long long sum;
double d[N];
map<int,int>mp;
map<int,int>::iterator it;
struct daodan{
int id,x;
double d;
};
bool cmp(daodan a,daodan b){
return a.x>b.x;
}
bool Cmp(int a,int b){
return a>b;
}
vector<daodan>t[N];
void add(int x){
for(;x<=s;x+=x&-x)T[x]++;
}
int get(int x){
int ans=0;
for(;x;x-=x&-x)ans+=T[x];
return ans;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>x>>y>>v;
if(!mp[y])mp[y]=++id;
t[mp[y]].push_back({i,x,x+v*sqrt(2*y/g)});//对于每一个 y 坐标上的导弹分别求解
}
for(auto it:mp){
x=it.second,sort(t[x].begin(),t[x].end(),cmp),s=t[x].size();
for(int i=0;i<s;i++)d[i]=t[x][i].d;
sort(d,d+s);//树状数组求逆序对,前后都要求一次
for(int i=1;i<=s;i++)T[i]=0;
for(int i=0;i<s;i++){
t[x][i].d=upper_bound(d,d+s,t[x][i].d)-d;//离散化
V[t[x][i].id]+=get(t[x][i].d);
add(t[x][i].d);
}
for(int i=1;i<=s;i++)T[i]=0;
for(int i=s-1;i>=0;i--){
V[t[x][i].id]+=s-1-i-get(t[x][i].d-1);
add(t[x][i].d);
}
}
for(int i=1;i<=n;i++)cin>>a,sum+=V[i],f[i]=min(a,V[i]);//贪心部分
sort(f+1,f+1+n,Cmp);
for(int i=1;i<=m;i++)sum-=f[i];
cout<<sum;
}