【jzoj3771】【NOI2015模擬8.15】【小 Z 的煩惱】

題目大意

小 Z 最近遇上了大麻煩,他的數學分析掛科了。於是他只好找數分老師求情。

善良的數分老師答應不掛他,但是要求小 Z 幫助他一起解決一個難題問題是這樣的,現在有 n 個標號爲 1~n 的球和 m 個盒子,每個球都可以放進且只能放進一個盒子裏面,但是要滿足如下的規則:

1. 若把標號爲 i 的球放進了第 j 個盒子,那麼標號爲 2*i 的球一定要在第 j+1 個盒子裏面(若 j

2. 若把標號爲 i 的球放進了第 j 個盒子,並且 k*2=i,那麼標號爲 k 的球一定要在第 j-1 個盒子裏面(若 j>1)

小 Z 的數分老師想要知道,給定了 n 和 m 的時候,第一個盒子最多能放進去多少個球。事實上,他已經推算出了公式,但是需要檢驗當 n 趨向於無窮大時是否仍然滿足這個公式,因此 n 可能會非常大。

解題思路

可以發現第一個盒子數取值範圍爲1n/2m1 ,合法的數x集合爲首項爲2mx2mx+1x

ans=x=0n2mx2mx+1+1

=x=0n2mx+12

高精度位運算即可。

code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define ULL unsigned int
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
#define f2(i,j) for(int i=begi2[j];i;i=nex2[i])
using namespace std;
int const mn=500+2,inf=1e9+7;
int n,m,nn,K,a[mn][mn],b[mn*mn],c[mn][mn];
LL tot,f[mn*mn][2],g[mn*mn][2],sizeb0,sumb0;
void oper(int x,int y,int op){
    int l=c[x][y],p=l-1;
    LL q0=0,q1=0;
    while(p){
        q0+=f[p][0];
        q1+=f[p][1];
        p-=p&(-p);
    }
    q0<<=1;q1<<=1;
    tot+=op*((q0+g[l][0]-sizeb0)*a[x][y]-q1-g[l][1]+sumb0);
    sizeb0+=op;
    sumb0+=a[x][y]*op;
    g[l][0]+=op;
    g[l][1]+=a[x][y]*op;
    p=l;q0=a[x][y]*op;
    while(p<=nn){
        f[p][0]+=op;
        f[p][1]+=q0;
        p+=p&(-p);
    }
}
int main(){
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);
    fo(i,1,n)fo(j,1,m)scanf("%d",&a[i][j]),b[++b[0]]=a[i][j];
    sort(b+1,b+b[0]+1);
    int tmp=0;
    fo(i,1,b[0])if((i==1)||(b[i]!=b[i-1]))b[++tmp]=b[i];
    b[0]=tmp;nn=b[0];
    fo(x,1,n)fo(y,1,m){
        int l=1,r=b[0],md;
        while(l!=r){
            md=(l+r)>>1;
            if(b[md]<a[x][y])l=md+1;
            else r=md;
        }
        c[x][y]=l;
    }
    fo(i,1,K)fo(j,1,K)oper(i,j,1);
    LL ans=tot;
    fo(i,1,n-K+1){
        if(i&1){
            fo(j,1,m-K){
                fo(k,i,i+K-1)oper(k,j,-1),oper(k,j+K,1);
                ans+=tot;
            }
            if(i!=n-K+1){
                fo(k,m-K+1,m)oper(i,k,-1),oper(i+K,k,1);
                ans+=tot;
            }   
        }else{
            fd(j,m-K,1){
                fo(k,i,i+K-1)oper(k,j,1),oper(k,j+K,-1);
                ans+=tot;
            }
            if(i!=n-K+1){
                fo(k,1,K)oper(i,k,-1),oper(i+K,k,1);
                ans+=tot;
            }   
        }
    }
    printf("%lld",ans*2%10007);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章