题目七夕屠狗系列
这道题显然用线段树,但在最后枚举答案时我用上了模拟退火,最后万万没想到MLE了
退火邪教诚不欺我
代码先放上:
#pragma GCC opitimize(2)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<ctime>
using namespace std;
#define re register int
#define I_LOVE_YOU cout<<ans<<'\n';//七夕限定
const int N=1e5+5;
const double T=1e3;
const double cool=0.996;
const double mintemp=1e-10;
int n,w,tree[N<<2],maxx,ansx,ans;
struct Node{
int x;
int b;
}stars[N];
void add_data(int k,int l,int r,int x,int num)
{
if(l==r)
{
tree[k]+=num;
return;
}
int mid=(l+r)>>1;
if(x<=mid)add_data(k<<1,l,mid,x,num);
else add_data(k<<1|1,mid+1,r,x,num);
tree[k]=tree[k<<1]+tree[k<<1|1];
}
int ask(int k,int l_now,int r_now,int l,int r)
{
if(l>maxx)return 0;
if(r>maxx&&l<=maxx)r=maxx;
if(l<=l_now&&r_now<=r)return tree[k];
int mid=(l_now+r_now)>>1,res=0;
if(l<=mid)res+=ask(k<<1,l_now,mid,l,r);
if(mid<r)res+=ask(k<<1|1,mid+1,r_now,l,r);
return res;
}
inline void SA()
{
double temp=T;
while(temp>mintemp)
{
double nx;
nx=ansx+(double)(rand()*2-RAND_MAX)*temp;
if(nx<0)continue;
nx=ceil(nx);
int nans=ask(1,1,n,nx,nx+w-1);
int dealt=nans-ans;
if(dealt>0)
{
ansx=nx;
ans=nans;
}
else if(exp((double)dealt/temp)>rand())ansx=nx;
temp*=cool;
}
}
int main()
{
//freopen("P3353_2.in","r",stdin);
//freopen("P3353.out","w",stdout);
srand(time(NULL));srand(rand());
ios::sync_with_stdio(false);
memset(tree,0,sizeof(tree));
cin>>n>>w;
if(!w)
{
I_LOVE_YOU
return 0;
}
for(re i=1;i<=n;++i)
{
cin>>stars[i].x>>stars[i].b;
maxx=max(maxx,stars[i].x);
}
for(re i=1;i<=n;++i)add_data(1,1,maxx,stars[i].x,stars[i].b);
ansx=1;
ans=ask(1,1,maxx,ansx,ansx+w-1);
while((double)clock()/CLOCKS_PER_SEC<0.8)SA();
I_LOVE_YOU
return 0;
}
最后调试发现是退火里边“int nans=ask(1,1,n,nx,nx+w-1);”导致了MLE。也没有多余地消耗数组,百思不得其解,用了很多次函数会MLE吗?