BZOJ4092: [Zjoi2015]幻想乡Wifi搭建计划

我承认我是SB
我看到网上没有题解 那我就来写一篇好了
(本文发出来十分钟之后被Claris直接打脸
很多人(包括我 看到这一题会认为这个是网络流 然后一直想该怎么建模。。。 后来lbn教了我这一题的做法(%%%%%
先处理出可以被WIFI覆盖的景点 弹入一个序列 S
然后将 S 中的元素按x大小排序
f[i][j][k] 表示上面取了前j个圆 下面取了前k个圆
我们就有一个DP的式子(lbn给我的
f[i][j][k]>f[i+1][j][k](ji+1||ki+1)
f[i][j][k]+cost[l]>f[i+1][l][k](li)
f[i][j][k]+cost[l]>f[i+1][j][l](li)
然后 O(n^4) 扫一遍
为什么这样子做是正确的呢?
我们来看一下每个圆被记录贡献的情况
当我们扫到第 i 个景点时 我们需要用以往的状态去更新 f[i][...][...] 如果我们盲目的不排序去 O(n4) 扫一遍 显然其中会有许多圆被重复计算
如果我们排过序 那么我们就可以保证每个圆只被一个 f[i][j][k] 计算一次贡献 因为每个圆被弹入 f[i][j][k] 当且仅当当前他没有被加入前驱态

我觉得我没有说清楚。。。但是肯定说不清楚了。。。真的不懂看代码应该会懂

#include
#include
#include
#include
using namespace std;
#define ll long long
struct P
{
    ll x,y,c;
    inline bool friend operator <(P a,P b){return a.x^b.x?a.xchar c;
bool flag;
inline void read(ll &a)
{
    a=0;do c=getchar();while((c<'0'||c>'9')&&c!='-');
     if(c=='-')c=getchar(),flag=true;
    while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
    if(flag)a=-a,flag=false;
}

ll R;
inline ll Dis(P a,P b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
inline bool Con(P a,P b){return Dis(a,b)<=R*R;}
ll F[101][101][101];
P Up[10001],Low[10001],Fl[1001],Cache[101],Cache2[101];
ll cost[101];
const
 ll INF=1ll<<59;
ll n,m;
int main()
{
    read(n),read(m),read(R);
    for(ll i=1;i<=n;i++)
     read(Cache[i].x),read(Cache[i].y);
    for(ll i=1;i<=m;i++)
      read(Cache2[i].x),read(Cache2[i].y),read(Cache2[i].c);
    ll ans=0,tot=0;
    for(ll i=1;i<=n;i++) 
     {
      for(ll j=1;j<=m;j++)
         if(Con(Cache[i],Cache2[j])){ans++;goto ed;}
      continue;
     ed:Fl[++tot]=Cache[i];
    } 
   ll M1=0,M2=0;
      for(ll j=1;j<=m;j++)
       if(Cache2[j].y<0)
         Low[++M2]=Cache2[j];
        else 
         Up[++M1]=Cache2[j];
    sort(Fl+1,Fl+tot+1);
    F[0][0][0]=0;
     for(ll k=1;k<=M2;k++)
       F[0][0][k]=F[0][0][k-1]+Low[k].c;
    for(ll j=1;j<=M1;j++)
      for(ll k=0;k<=M2;k++)
        F[0][j][k]=(k==0?(F[0][j-1][0]+Up[j].c):(F[0][j][k-1]+Low[k].c));

    F[0][0][0]=0;
    for(ll i=1;i<=tot;i++)
     for(ll j=0;j<=M1;j++)
      for(ll k=0;k<=M2;k++)
       {
          F[i][j][k]=INF; 
          if(Con(Up[j],Fl[i])&&j)
                for(ll l=0;l<=M1;l++)
                  F[i][j][k]=min(F[i][j][k],F[i-1][l][k]+Up[j].c);
          if(Con(Low[k],Fl[i])&&k)
                for(ll l=0;l<=M2;l++)
                  F[i][j][k]=min(F[i][j][k],F[i-1][j][l]+Low[k].c);   
             if(Con(Up[j],Fl[i])&&j)
               F[i][j][k]=min(F[i][j][k],F[i-1][j][k]);
             if(Con(Low[k],Fl[i])&&k)
               F[i][j][k]=min(F[i][j][k],F[i-1][j][k]);
       }
    printf("%lld\n",ans);
    ans=INF;
     for(ll j=0;j<=M1;j++)
      for(ll k=0;k<=M2;k++)
       ans=min(ans,F[tot][j][k]);
    printf("%lld\n",ans);
    return 0;
} 

你可能感兴趣的:(DP,乱搞)