您的位置:首页 > 其它

2017.9.24 虔诚的墓主人 思考记录

2017-09-24 18:17 267 查看
这个题是纯信息处理题、

首先要明白,对墓地进行枚举是会T的,需要对常青树进行枚举

所以枚举的顺序也要注意:一定要按某种顺序

然后要明白,每一个常青树会对列和行都造成影响,对答案有贡献的点只会在两个点之间

所以可以枚举区间,然后看区间满足两个条件的个数

所以可以用类似线段树dp的思想,一遍查一边改,同时枚举的时候增加/消除影响,就可以做了

码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
#define N 100005
#define ll long long
#define P 2147483648
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
ll he[N<<2],lie
,tong
,a,b,c,x,y,k,jc
,ni
,n,m,g,tong2
,jishu;
map<int,int>dui,dui2;
ll ans,lin,zhs
[15];
struct la
{
ll x,y;
}s
;

bool cmp(la a,la b)
{
return a.y<b.y;
}
bool cmp2(la a,la b)
{
if(a.x!=b.x)
return a.x<b.x;
else return a.y<b.y;
}

void up(ll o)
{
he[o]=(he[o<<1]+he[o<<1|1])%P;
}

void cha(ll o,ll l,ll r)
{
if(a<=l&&r<=b)
{
lin+=he[o];
lin%=P;
return;
}
ll mid=(r+l>>1);
if(a<=mid)cha(zuo);
if(b>mid)cha(you);

}
ll C(ll a,ll b)
{
if(a<b)return 0;
return zhs[a][b];
}

void gai(int o,int l,int r)
{
if(l==r)
{

he[o]=1ll*C(tong[c]-lie[c],k)*C(lie[c],k)%P;
return ;
}
int mid=(l+r)>>1;
if(a<=mid)gai(zuo);
if(b>mid)gai(you);
up(o);
}

int main()
{int i,j;
scanf("%lld%lld%lld",&n,&m,&g);
n=g;
zhs[0][0]=1;

for(i=1;i<=g;i++)
{
scanf("%lld%lld",&s[i].x,&s[i].y);
}
scanf("%lld",&k);
for(i=1;i<=n;i++)
{zhs[i][0]=1;
for(j=1;j<=k;j++)
{
zhs[i][j]=1ll*zhs[i-1][j]+zhs[i-1][j-1]%P;
// cout<<zhs[i][j];
}
//cout<<endl;
}
sort(s+1,s+1+n,cmp);

for(i=1;i<=n;i++)
{
dui[s[i].y]=i;
}
for(i=1;i<=n;i++)
{
tong[dui[s[i].y]]++;
}
sort(s+1,s+1+n,cmp2);
for(i=1;i<=n;i++)
{
dui2[s[i].x]=i;
}
for(i=1;i<=n;i++)
{
tong2[dui2[s[i].x]]++;
}
for(i=1;i<=n;i++)
{
if(s[i].x==s[i-1].x&&i!=1)//在同一行
{++jishu;
a=dui[s[i-1].y]+1;
b=dui[s[i].y]-1;
lin=0;
if(a<=b)cha(1,1,n);//统计区间答案
if(lin>0)
{
ans+=lin*C(jishu-1,k)%P*C(tong2[dui2[s[i].x]]-jishu+1,k); //夹两边
ans%=P;
}
}else
{
jishu=1;
}
lie[dui[s[i].y]]++;
a=b=c=dui[s[i].y];
gai(1,1,n);
}

printf("%lld",(ans+P)%P);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: