虔诚的墓主人

E. 虔诚的墓主人

内存限制:512 MiB 时间限制:1000 ms 标准输入输出
 
 
题目描述

小W 是一片新造公墓的管理人。公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地。当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地。为了体现自己对主的真诚,他们希望自己的墓地拥有着较高的虔诚度。一块墓地的虔诚度是指以这块墓地为中心的十字架的数目。一个十字架可以看成中间是墓地,墓地的正上、正下、正左、正右都有恰好k 棵常青树。小W 希望知道他所管理的这片公墓中所有墓地的虔诚度总和是多少

输入格式

第一行包含两个用空格分隔的正整数N 和M,表示公墓的宽和长,因此这个矩形公墓共有(N+1) ×(M+1)个格点,左下角的坐标为(0, 0),右上角的坐标为(N, M)。第二行包含一个正整数W,表示公墓中常青树的个数。第三行起共W 行,每行包含两个用空格分隔的非负整数xi和yi,表示一棵常青树的坐标。输入保证没有两棵常青树拥有相同的坐标。最后一行包含一个正整数k,意义如题目所示。

输出格式

包含一个非负整数,表示这片公墓中所有墓地的虔诚度总和。为了方便起见,答案对2,147,483,648 取模。

样例
样例输入
5 6
13
0 2
0 3
1 2
1 3
2 0
2 1
2 4
2 5
2 6
3 2
3 3
4 3
5 2
2
样例输出
6
数据范围与提示

图中,以墓地(2, 2)和(2, 3)为中心的十字架各有3个,即它们的虔诚度均为3。其他墓地的虔诚度为0。 所有数据满足1 ≤ N, M ≤ 1,000,000,000,0 ≤ xi ≤ N,0 ≤ yi ≤ M,1 ≤ W ≤ 100,000, 1 ≤ k ≤ 10。存在50%的数据,满足1 ≤ k ≤ 2。存在25%的数据,满足1 ≤ W ≤ 10000。 注意:”恰好有k颗树“,这里的恰好不是有且只有,而是从>=k的树中恰好选k棵

 这题首先一看,墓主人!!!因森森的,背后一阵寒气,然后搜索暴力浮现在脑中,一划滚轮,看见的数据范围,噗~~~~(一口老血), 这题变态吧!
                                                                                ------------先不扯×了;----------------
当然一看提首先想到的是暴力,但是数据范围那么多0( 就知道这题要爆零)想到数据这么大,如果使用矩阵进行模拟,板× (消费一波pa大婶)会MLE,按N和M开数组一定会RE带MLE,所以我们选择稍微小一点的W作为数组的大小,并且只能开一维,所以按W来,就要离散化(使用骗分神器lower_bound())一波操作之后,就可以臆想一个W*W数组(千万不要开出来!)很简单的就想到时间复杂度逼近O(n^3)的程序,明显TLE;
就是暴力枚举!
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<vector>
  5 #include<algorithm>
  6 #define LL unsigned long long
  7 using namespace std;
  8 LL n,m,w,k;
  9 const LL maxn=10005;
 10 struct point{
 11     LL x,y,z,lisany,lisanx;
 12 }ac[100050];
 13 LL biao[12000][12000];
 14 const LL mod=2147483646;
 15 LL ans=0;
 16 LL C[100005][15];
 17 inline LL read()
 18 {
 19     LL x=0,f=1;char c=getchar();
 20     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
 21     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
 22     return x*f;
 23 }
 24 bool cmp2(point a,point b){return a.y<b.y;}
 25 bool cmp3(point a,point b){return a.x<b.x;}
 26 int main()
 27 {
 28     //freopen("cnm.txt","r",stdin);
 29     n=read(),m=read();
 30     w=read();
 31     for(LL i=1;i<=w;i++)
 32     {
 33         LL bb=read(),cc=read();
 34         ac[i]=(point){bb,cc,0,0};
 35     }/*
 36     for(int i=0;i<=w;i++)
 37     {
 38         for(int j=0;j<=w;j++)
 39             printf("%lld ",lop[i][j]);
 40         printf("\n");    
 41     }
 42 
 43     printf("\n");*/
 44     k=read();
 45     C[0][0]=1;
 46     for(LL i=1;i<=w;++i)
 47     {
 48         C[i][0]=1;
 49         for(LL j=1;j<=k;++j)
 50             C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
 51     }
 52     sort(ac+1,ac+w+1,cmp2);
 53     LL thistot=0,thisy=ac[1].y;
 54     for(LL i=1;i<=w;i++)
 55         if(ac[i].y==thisy)
 56         {
 57             ac[i].lisany=thistot;
 58         }
 59         else 
 60         {
 61             ++thistot;
 62             ac[i].lisany=thistot;
 63             thisy=ac[i].y;
 64         }
 65     sort(ac+1,ac+w+1,cmp3);
 66     thistot=0;LL thisx=ac[1].x;
 67     for(LL i=1;i<=w;i++)
 68         if(ac[i].x==thisx)
 69         {
 70             ac[i].lisanx=thistot;
 71         }
 72         else 
 73         {
 74             ++thistot;
 75             ac[i].lisanx=thistot;
 76             thisx=ac[i].x;
 77         }
 78     LL maxx=0,maxy=0;
 79     for(LL i=1;i<=w;i++)
 80         biao[ac[i].lisanx][ac[i].lisany]=1,maxx=max(maxx,ac[i].lisanx),maxy=max(maxy,ac[i].lisany);
 81 /*
 82     for(int i=0;i<=w;i++)
 83     {
 84         for(int j=0;j<=w;j++)
 85             printf("%lld ",biao[i][j]);
 86         printf("\n");
 87     }
 88     */
 89     for(LL i=1;i<=maxx;i++)
 90         for(LL j=1;j<=maxy;j++)
 91         {
 92             if(biao[i][j])continue;
 93             LL up=0,down=0,left=0,right=0;
 94             for(LL a=0;a<i;a++)if(biao[a][j])left++;
 95             for(LL a=i+1;a<=maxx;a++)if(biao[a][j])right++;
 96             for(LL a=0;a<j;a++)if(biao[i][a])down++;
 97             for(LL a=j+1;a<=maxy;a++)if(biao[i][a])up++;
 98             //printf("%lld %lld %lld  %lld  %lld  %lld\n",i,j,left,right,up,down);
 99             if(left>=k&&right>=k&&up>=k&&down>=k)
100                 ans+=(((((C[left][k]*C[right][k])%mod)*C[up][k])%mod)*C[down][k])%mod;
101         }
102     printf("%lld\n",ans);
103     return 0;
104 }
暴力暴力W12

显然是ans=sigama(C(up,k)*C(down,k)*C(left,k)*C(right,k));

显然这个不能通过;
所以还是老老实实的写正解吧(然后三节课就过去了!)我想到了如何优化暴力,就是让他离散化之后维护他左侧的前缀和和上方的前缀和,让这一列的树的棵树减去上方得到下方的树的棵树,同理解的右侧的树的棵树;
那么就维护前缀和,O(n^2);
那么数据结构优化(树状数组)维护一下O(n)逼近而已;
至于组合数,楊輝三角起来杠;
 
我的Ac代码如下
     题目    状态    分数    总时间    内存    提交者    提交时间
#77724    
#E. 虔诚的墓主人

    Accepted     100    1613 ms    22504 KiB    lsc     2019-07-04 11:35:11
 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 #define LL long long 
 7 struct fhsb{
 8     LL x,y;
 9 };
10 const LL N=1e6+5,P=2147483648;
11 LL x[N],y[N],C[N][20];
12 LL t[N],s[N],w;;
13 LL lie[N],hang[N];
14 fhsb p[N];
15 bool cmp(fhsb a,fhsb b){if(a.x==b.x)return a.y<b.y;else return a.x<b.x;}
16 inline LL lowbit(LL x){return x&(-x);}
17 inline LL read()
18 {
19     LL x=0,f=1;char c=getchar();
20     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
21     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
22     return x*f;
23 }
24 inline void update(LL x,LL v)
25 {
26     v%=P;
27     while(x<=w)
28     {
29         s[x]=(s[x]+v)%P;
30         x+=lowbit(x);
31     }
32 }
33 
34 inline LL sum(LL x)
35 {
36     int res=0;
37     while(x)
38     {
39         res=(res+s[x])%P;
40         x-=lowbit(x);
41     }
42     return res;
43 }
44 int main()
45 {
46     freopen("cnm.txt","r",stdin);
47     read();read();
48     w=read();
49     for(LL i=1;i<=w;++i) 
50     {
51         x[i]=p[i].x=read();
52         y[i]=p[i].y=read();
53     }
54     LL k=read();
55     C[0][0]=1;
56     for(LL i=1;i<=w;++i)
57     {
58         C[i][0]=1;
59         for(LL j=1;j<=k;++j)
60             C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
61     }
62     sort(x+1,x+w+1);
63     sort(y+1,y+w+1);
64     for(LL i=1;i<=w;++i) 
65         p[i].x=lower_bound(x+1,x+w+1,p[i].x)-x,lie[p[i].x]++;
66     for(LL i=1;i<=w;++i) 
67         p[i].y=lower_bound(y+1,y+w+1,p[i].y)-y,hang[p[i].y]++;
68     sort(p+1,p+w+1,cmp);
69     LL down=1,ans=0;
70     for(LL i=1;i<w;++i)
71     {
72         if(p[i].x==p[i-1].x) down++;
73         else down=1;
74         LL up=lie[p[i].x]-down;
75         if(up)
76         {
77             LL ccf=p[i+1].y-1;
78             ans+=C[down][k]*C[up][k]%P*((sum(ccf)-sum(p[i].y)%P+P)%P);
79         }
80         ++t[p[i].y];
81         LL now=C[t[p[i].y]][k]*C[hang[p[i].y]%P-t[p[i].y]][k]%P;
82         LL pre=(sum(p[i].y)-sum(p[i].y-1)+P)%P;
83         update(p[i].y,((now-pre+P)%P));
84     }
85     printf("%lld\n",((ans+P)%P+P)%P);
86     return 0;
87 }
AC

其实有人想问,这么水的题你还调了一上午,我只想说,都是编译器惹得祸;

编译器对要模的数2,147,483,648最大%2147483647,然后我就打的2147483647,一直WA16,其实OJ可以交2147483648,所以卡了一上午;

 编号    题目    状态    分数    总时间    内存    提交者    提交时间
#77724    
#E. 虔诚的墓主人

    Accepted     100    1613 ms    22504 KiB    lsc     2019-07-04 11:35:11
#77718    
#E. 虔诚的墓主人

    Wrong Answer     16    1747 ms    22496 KiB    lsc     2019-07-04 11:33:36
#77706    
#E. 虔诚的墓主人

    Wrong Answer     16    1775 ms    22504 KiB    lsc     2019-07-04 11:27:12
#77702    
#E. 虔诚的墓主人

    Compile Error                    lsc     2019-07-04 11:26:30
#77698    
#E. 虔诚的墓主人

    Wrong Answer     16    1531 ms    22376 KiB    lsc     2019-07-04 11:23:53
#77695    
#E. 虔诚的墓主人

    Wrong Answer     16    1536 ms    22504 KiB    lsc     2019-07-04 11:21:31
#77691    
#E. 虔诚的墓主人

    Wrong Answer     16    1561 ms    22504 KiB    lsc     2019-07-04 11:20:37
#77689    
#E. 虔诚的墓主人

    Wrong Answer     0    1855 ms    22628 KiB    lsc     2019-07-04 11:19:45
#77680    
#E. 虔诚的墓主人

    Wrong Answer     0    1463 ms    22504 KiB    lsc     2019-07-04 11:12:52
#77675    
#E. 虔诚的墓主人

    Wrong Answer     16    1543 ms    22504 KiB    lsc     2019-07-04 11:10:07
#77665    
#E. 虔诚的墓主人

    Wrong Answer     16    1529 ms    22500 KiB    lsc     2019-07-04 11:04:48
#77664    
#E. 虔诚的墓主人

    Wrong Answer     16    1528 ms    22504 KiB    lsc     2019-07-04 11:03:41
#77661    
#E. 虔诚的墓主人

    Wrong Answer     16    1548 ms    22496 KiB    lsc     2019-07-04 11:02:33
#77658    
#E. 虔诚的墓主人

    Wrong Answer     16    1577 ms    22504 KiB    lsc     2019-07-04 11:01:25
#77657    
#E. 虔诚的墓主人

    Time Limit Exceeded     12    19259 ms    5096 KiB    lsc     2019-07-04 11:00:15
#77652    
#E. 虔诚的墓主人

    Time Limit Exceeded     12    19368 ms    5096 KiB    lsc     2019-07-04 10:58:39
#77650    
#E. 虔诚的墓主人

    Time Limit Exceeded     0    25188 ms    496 KiB    lsc     2019-07-04 10:57:29
#77642    
#E. 虔诚的墓主人

    Wrong Answer     48    1359 ms    9576 KiB    lsc     2019-07-04 10:54:14
#77428    
#E. 虔诚的墓主人

    Time Limit Exceeded     0    25191 ms    492 KiB    lsc     2019-07-03 16:30:10
#77400    
#E. 虔诚的墓主人

    Runtime Error     12    17904 ms    319464 KiB    lsc     2019-07-03 16:14:16
#77380    
#E. 虔诚的墓主人

    Runtime Error     12    17865 ms    331116 KiB    lsc     2019-07-03 15:59:26
#77377    
#E. 虔诚的墓主人

    Time Limit Exceeded     0    25416 ms    492 KiB    lsc     2019-07-03 15:58:42
#77354    
#E. 虔诚的墓主人

    Runtime Error     0    2022 ms    330056 KiB    lsc     2019-07-03 15:42:01
#77346    
#E. 虔诚的墓主人

    Time Limit Exceeded     0    25206 ms    488 KiB    lsc     2019-07-03 15:36:37
#77232    
#E. 虔诚的墓主人

    Compile Error                    lsc    2019-07-02 17:20:22
#77166    
#E. 虔诚的墓主人

    Runtime Error     0    127 ms    844 KiB    lsc    2019-07-02 14:38:34

副yxm大神的暴力AC

 1 #include<map>//n2 bruce
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define unt unsigned int
 5 #define maxn 100005
 6 #define mod 0x7fffffff
 7 using namespace std;
 8 int n,m;
 9 int c[maxn][11];
10 struct tree
11 {
12     int x,y;
13     bool friend operator <(tree a,tree b)
14     {return a.x==b.x?a.y<b.y:a.x<b.x;}
15 }p[maxn];
16 int szx,szy,z[maxn];
17 int binx[maxn],biny[maxn];
18 int ans;
19 void init()
20 {
21     scanf("%d%d%d",&n,&n,&n);
22     for(int i=1;i<=n;++i)
23         scanf("%d%d",&p[i].x,&p[i].y);
24     scanf("%d",&m);
25     map<int,int>mpx,mpy;
26     z[0]=-1;
27     for(int i=1;i<=n;++i) z[i]=p[i].x;
28     sort(z+1,z+1+n);
29     for(int i=1;i<=n;++i) 
30         if(z[i]!=z[i-1])
31             mpx[z[i]]=++szx;
32     for(int i=1;i<=n;++i) p[i].x=mpx[p[i].x],++binx[p[i].x];
33 
34     for(int i=1;i<=n;++i) z[i]=p[i].y;
35     sort(z+1,z+1+n);
36     for(int i=1;i<=n;++i)
37         if(z[i]!=z[i-1]) 
38             mpy[z[i]]=++szy;
39     for(int i=1;i<=n;++i) p[i].y=mpy[p[i].y],++biny[p[i].y];
40 
41     sort(p+1,p+1+n);
42     for(int i=0;i<=n;++i)
43     {
44         c[i][0]=1;
45         for(int j=1;j<=m&&j<=i;++j)
46             c[i][j]=c[i-1][j-1]+c[i-1][j];
47     }
48 }
49 int bin[maxn],ab,cnt;
50 void calc(int x)
51 {
52     for(int i=1;i<=szy;++i)
53     {
54         if(x==p[cnt+1].x&&i==p[cnt+1].y)
55         {++ab;++bin[i];++cnt;continue;}
56         ans+=c[bin[i]][m]*c[biny[i]-bin[i]][m]*c[ab][m]*c[binx[x]-ab][m];
57         //printf("%d %d (%d %d) up %d lf %d\n",x,i,binx[x],biny[i],ab,bin[i]);
58     }
59 }
60 int main()
61 {
62     init();
63     for(int i=1;i<=szx;++i)
64     {
65         ab=0;
66         calc(i);
67     }
68     printf("%d\n",ans&mod);
69 }
70 /*
71 5 6
72 13
73 0 2
74 0 3
75 1 2
76 1 3
77 2 0
78 2 1
79 2 4
80 2 5
81 2 6
82 3 2
83 3 3
84 4 3
85 5 2
86 2
87 */
YXM

 

我太菜了!!!!!!!!!!!!!!!!!!!!!!

 

转载于:https://www.cnblogs.com/hzoi-lsc/p/11131654.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值