• [cf1086F]Forest Fires


    记$f(i)$表示时刻$i$时着火的格子数,则答案即$t\cdot f(t)-\sum_{i=0}^{t-1}f(i)$

    关于$f(i)$,即对所有点为中心、边长为$2i+1$​的矩形求并,容斥可得
    $$
    f(i)=\sum_{S\subseteq [1,n],S\ne \empty}(-1)^{|S|-1}\max(2i+1-d_{x}(S),0)\max(2i+1-d_{y}(S),0)
    $$
    (其中$d_{x/y}(S)$分别表示$S$中所有点$x$或$y$坐标的极差)

    注意到可行的$d_{x}(S)$或$d_{y}(S)$均仅有$o(n^{2})$个,因此$f(i)$是一个$o(n^{2})$段的二次函数

    对于每一段,仅需求出三个$f(i)$即可得到该函数,且单次(矩形求并)复杂度为$o(n\log n)$

    总复杂度为$o(n^{3}\log n)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 60
     4 #define mod 998244353
     5 #define ll long long
     6 #define pii pair<int,int>
     7 #define L (k<<1)
     8 #define R (L+1)
     9 #define mid (l+r>>1)
    10 int T,n,t,ans,x[N],y[N],yl[N],yr[N],tag[N<<3],g[N<<3],f[N<<3];
    11 vector<int>v0,vx,vy;vector<pii>v[N<<1];
    12 int S1(int k){
    13     return (ll)k*(k+1)%mod*(mod+1>>1)%mod;
    14 }
    15 int S2(int k){
    16     return (ll)k*(k+1)%mod*((k<<1)+1)%mod*(mod+1)/6%mod;
    17 }
    18 int findx(int k){
    19     return lower_bound(vx.begin(),vx.end(),k)-vx.begin()+1;
    20 }
    21 int findy(int k){
    22     return lower_bound(vy.begin(),vy.end(),k)-vy.begin()+1;
    23 }
    24 void update(int k,int l,int r,int x,int y,int z){
    25     if ((l>y)||(x>r))return;
    26     if ((x<=l)&&(r<=y)){
    27         tag[k]+=z,f[k]=(tag[k] ? vy[r]-vy[l-1] : g[k]);
    28         return;
    29     }
    30     update(L,l,mid,x,y,z),update(R,mid+1,r,x,y,z);
    31     g[k]=f[L]+f[R],f[k]=(tag[k] ? vy[r]-vy[l-1] : g[k]);
    32 }
    33 int calc(int k){
    34     vx.clear(),vy.clear();
    35     for(int i=1;i<=(n<<1);i++)v[i].clear();
    36     for(int i=1;i<=n;i++){
    37         vx.push_back(x[i]-k),vx.push_back(x[i]+k+1);
    38         vy.push_back(y[i]-k),vy.push_back(y[i]+k+1);
    39     }
    40     sort(vx.begin(),vx.end()),sort(vy.begin(),vy.end());
    41     for(int i=1;i<=n;i++){
    42         yl[i]=findy(y[i]-k),yr[i]=findy(y[i]+k+1)-1;
    43         v[findx(x[i]-k)].push_back(make_pair(i,1));
    44         v[findx(x[i]+k+1)].push_back(make_pair(i,-1));
    45     }
    46     int ans=0;
    47     for(int i=1;i<=(n<<1);i++){
    48         for(pii j:v[i])update(1,1,(n<<1)-1,yl[j.first],yr[j.first],j.second);
    49         if (i<(n<<1))ans=(ans+(ll)(vx[i]-vx[i-1])*f[1])%mod;
    50     }
    51     return ans;
    52 }
    53 int calc(int l,int r){
    54     if (l>r)return 0;
    55     if (l==r)return calc(l);
    56     if (l+1==r)return (calc(l)+calc(l+1))%mod;
    57     int c=calc(l),s1=calc(l+1),s2=calc(l+2);
    58     s1=(s1-c+mod)%mod,s2=(s2-c+mod)%mod;
    59     int a=((ll)s2*(mod+1>>1)-s1+mod)%mod,b=(s1-a+mod)%mod;
    60     return ((ll)a*S2(r-l)+(ll)b*S1(r-l)+(ll)c*(r-l+1))%mod;
    61 }
    62 int main(){
    63     scanf("%d%d",&n,&t);
    64     for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]);
    65     ans=(ll)t*calc(t)%mod;
    66     v0.push_back(t);
    67     for(int i=1;i<=n;i++)
    68         for(int j=i+1;j<=n;j++)
    69             v0.push_back(max(abs(x[i]-x[j]),abs(y[i]-y[j]))+1>>1);
    70     sort(v0.begin(),v0.end());
    71     int l=0;
    72     for(int i=0;(i<v0.size())&&(v0[i]<=t);i++)ans=(ans-calc(l,v0[i]-1)+mod)%mod,l=v0[i];
    73     printf("%d\n",ans);
    74     return 0;
    75 }
    View Code

    交换求和顺序,答案也即$\sum_{S\subseteq [1,n],S\ne \empty}(-1)^{|S|-1}F(d_{x}(S),d_{y}(S))$

    其中$F(x,y)$为后式的总贡献(带系数),简单推导后可以$o(1)$计算

    将所有点按$x$坐标排序(相同时任意),并枚举$S$(在序列中)最左和最右两点

    此时已经确定$x$坐标的两个极值,并考虑枚举$y$坐标的两个极值,从而确定$d_{x/y}(S)$

    四个极值即构成一个矩形,并注意到以下性质:

    若矩形内除上下边界和选定的两点外存在其余的点,该点并不影响$d_{x/y}(S)$,进而使得贡献抵消

    换言之,上下边界均至多"拓展"一次,总共仅有$2\times 2=4$种可能

    具体实现中,可以倒序枚举右侧的点,并用链表维护两者之间的点($y$坐标)即可

    另外,关于$S$的$(-1)^{|S|-1}$之和,可以通过全体(为0)减去上/下边界全不选的情况

    总复杂度为$o(n^{2})$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 60
     4 #define mod 998244353
     5 #define ll long long
     6 #define fi first
     7 #define se second
     8 int T,n,t,ans,b[N],cnt[N],pre[N],nex[N];
     9 pair<int,int>a[N];
    10 int S1(int k){
    11     return (ll)k*(k+1)%mod*(mod+1>>1)%mod;
    12 }
    13 int S2(int k){
    14     return (ll)k*(k+1)%mod*((k<<1)+1)%mod*(mod+1)/6%mod;
    15 }
    16 int calc(int x,int y){
    17     x=(t<<1)+1-x,y=(t<<1)+1-y;
    18     if ((x<0)||(y<0))return 0;
    19     int d=(min(x,y)>>1),ans=(ll)t*x%mod*y%mod;
    20     ans=(ans-4LL*S2(d)%mod+mod)%mod;
    21     ans=(ans+2LL*S1(d)*(x+y))%mod;
    22     ans=(ans-(ll)d*x%mod*y%mod+mod)%mod;
    23     return ans;
    24 }
    25 int main(){
    26     scanf("%d%d",&n,&t);
    27     for(int i=1;i<=n;i++){
    28         scanf("%d%d",&a[i].fi,&a[i].se);
    29         b[i]=a[i].se;
    30     }
    31     sort(a+1,a+n+1),sort(b+1,b+n+1);
    32     for(int i=1;i<=n;i++)a[i].se=lower_bound(b+1,b+n+1,a[i].se)-b;
    33     ans=(ll)n*calc(0,0)%mod;
    34     for(int i=1;i<=n;i++){
    35         memset(cnt,0,sizeof(cnt));
    36         for(int j=i;j<=n;j++)cnt[a[j].se]++;
    37         int lst=0;
    38         for(int j=1;j<=n;j++)
    39             if (cnt[j])pre[j]=lst,nex[lst]=j,lst=j;
    40         pre[0]=lst,nex[lst]=0;
    41         for(int j=n;j>i;j--){
    42             int k=a[j].se;
    43             if (--cnt[k]>(k==a[i].se))continue;
    44             if (cnt[a[i].se]==1){
    45                 int l=a[j].fi-a[i].fi,x=a[i].se,y=a[j].se;
    46                 if (x>y)swap(x,y);
    47                 if ((x==y)||(nex[x]==y)){
    48                     ans=(ans-calc(l,b[y]-b[x])+mod)%mod;
    49                     if (pre[x])ans=(ans+calc(l,b[y]-b[pre[x]]))%mod;
    50                     if (nex[y])ans=(ans+calc(l,b[nex[y]]-b[x]))%mod;
    51                     if ((pre[x])&&(nex[y]))ans=(ans-calc(l,b[nex[y]]-b[pre[x]])+mod)%mod;
    52                 }
    53             }
    54             if (!cnt[k])pre[nex[k]]=pre[k],nex[pre[k]]=nex[k];
    55         }
    56     }
    57     printf("%d\n",ans);
    58     return 0;
    59 }
    View Code
  • 相关阅读:
    学英语舌尖效应(转)
    winform程序防止重复运行
    label字符自动换行(转自网络)
    C# WINFORM中的combobox.items.add实现像web开发那样,添加显示内容text和实际value值
    三极管开关电路设计(转)
    ASPNET+ArcGIS+Flex初次使用笔记
    转:oracle日期函数集锦
    网站开发人员应该知道的62件事
    cassandra的安装与使用
    datejs一个很好用的时间日期JavaScript组件
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/16213435.html
Copyright © 2020-2023  润新知