Time Limit: 5 Sec | Memory Limit: 259 MB |
---|
小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棵
刚看到恰好k颗的时候很是不解,后来看到hint的时候才知道所谓的恰好k颗竟然指的是从>=k的树中恰好选k棵,。。。Orz。。。
那么对于一个确定的墓地,如果我们已经知道在他的上下左右的常青树的个数为l,r,d,u。那么他的虔诚度为
我们将常青树的坐标按照想x,y排序,对于一个常青树 xi,yi ,已知在同一横坐标中的树的数量和在他左侧数的数量(我们可以预处理出来),那么在他和左边的树之间的墓碑在横坐标的常青树的组合是一样的为
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int Max = 110000;
const LL Mod = 1LL<<31;
struct node {
LL x,y;
bool operator < (const node &a)const {
return (x==a.x)?y<a.y:x<a.x;
}
} p[Max];
LL c[Max][15],Tr[Max];
LL ux[Max],uy[Max];
int numr[Max],numc[Max];
int num[Max];
LL n,m,k,w;
void Init() {
c[0][0] = 1;
for(int i =1; i<Max; i++) {
c[i][0] =1;
for(int j = 1; j<=13; j++) c[i][j] =(c[i-1][j]+c[i-1][j-1])%Mod;
}
}
LL C(LL n, LL m) {
if(m>n) return 0;
return c[n][m];
}
int lowbite(int x) {
return x&(-x);
}
void upd(int x,LL d) {
d =(d%Mod+Mod)%Mod;
while(x<Max) {
(Tr[x]+=d)%=Mod;
x+=lowbite(x);
}
}
LL que(int x) {
LL ans = 0;
while(x>0) {
(ans+=Tr[x])%=Mod;
x-=lowbite(x);
}
return ans;
}
int Lower_bound(int L,int R,LL aim,LL *a) {
while(L<=R) {
int mid = (L+R)>>1;
if(aim == a[mid]) return mid;
if(a[mid] < aim) L = mid+1;
else R = mid-1;
}
return 0;
}
int main() {
Init();
while(~scanf("%lld %lld",&n,&m)) {
scanf("%lld",&w);
ux[0] = 0;
uy[0] = 0;
for(int i = 0; i<w; i++) {
scanf("%lld %lld",&p[i].x,&p[i].y);
ux[++ux[0]] = p[i].x;
uy[++uy[0]] = p[i].y;
}
scanf("%lld",&k);
sort(p,p+w);
sort(ux+1,ux+1+ux[0]);
sort(uy+1,uy+1+uy[0]);
int s = ux[0];
ux[0] =1;
numr[1] =1;
for(int i = 2; i<=s; i++) {
if(ux[i]!=ux[ux[0]]) {
ux[++ux[0]] = ux[i];
numr[ux[0]] = 1;
} else numr[ux[0]] ++;
}
s = uy[0];
uy[0] = 1;
numc[1] =1;
for(int i = 2; i<=s; i++) {
if(uy[i]!=uy[uy[0]]) {
uy[++uy[0]] = uy[i];
numc[uy[0]] = 1;
} else numc[uy[0]] ++;
}
memset(Tr,0,sizeof(Tr));
memset(num,0,sizeof(num));
LL ans = 0;
LL tep = 1;
for(int i = 0; i<w; i++) {
int Fx = Lower_bound(1,ux[0],p[i].x,ux);
int Fy = Lower_bound(1,uy[0],p[i].y,uy);
if(!i || p[i].x !=p[i-1].x) tep = 1;
else tep++;
if(tep != 1) {
int Prey = Lower_bound(1,uy[0],p[i-1].y,uy);
LL ant = ((C(tep-1,k)*C(numr[Fx]-tep+1,k)%Mod)*((que(Fy-1)-que(Prey))%Mod))%Mod;
ans = (ans+ant)%Mod;
}
upd(Fy,(C(num[Fy]+1,k)*C(numc[Fy]-num[Fy]-1,k))%Mod-(C(num[Fy],k)*C(numc[Fy]-num[Fy],k))%Mod);
num[Fy]++;
}
printf("%lld\n",ans);
}
return 0;
}
求 (ax+by)k 的展开中 xn∗ym 项的系数。由于系数可能很大,只要求输出除以 10007 的余数。
一行共五个整数,分别为 a,b,k,n,m
一个整数,为该项系数除以10007的余数。
1 1 3 1 2
3
30% 0<=k<=10,
50% a=1,b=1
100% 0<=k<=1000, 0<=n,m<=k 且 n+m=k, 0<=a,b<=100,000
NOIP2011 DAY2 factor
NOIP2011
简单的组合 ans=C(kn)anbm
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL Mod = 10007;
const int Max = 200010;
LL fac[Max],facv[Max];
LL Pow(LL n, LL m) {
LL ans = 1;
while(m) {
if(m&1) ans = (ans*n)%Mod;
n = (n*n)%Mod;
m>>=1;
}
return ans;
}
void Init(){
fac[0] = 1; facv[0] = 1;
for(int i =1;i<Max;i++) {
fac[i] = (fac[i-1]*i)%Mod;
facv[i] = Pow(fac[i],Mod-2);
}
}
LL C(LL n,LL m) {
if(m>n) return 0;
return ((fac[n]*facv[m])%Mod*facv[n-m])%Mod;
}
int a,b,k,n,m;
int main(){
Init();
while(~scanf("%d %d %d %d %d",&a,&b,&k,&n,&m)){
LL ans = ((C(k,n)*Pow(a,n))%Mod*Pow(b,m))%Mod;
printf("%d\n",(int)ans);
}
return 0;
}
Time Limit: 10 Sec | Memory Limit: 128 MB |
---|
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意三角形的三点不能共线。
输入一行,包含两个空格分隔的正整数m和n。
输出一个正整数,为所求三角形数量。
2 2
76
1<=m,n<=1000
对于不考虑共线的情况,总的方案数为 C(n∗m3) ,那么我们去除共线的情况,我们枚举贡共线的两端,然后将线段进行平移就可以计算出共线的个数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int Max = 1000100;
LL c[Max][4];
void Init(){
c[0][0] = 1;
for(int i =1;i<Max;i++) {
c[i][0] =1;
for(int j = 1;j<=3;j++) {
c[i][j] = c[i-1][j]+c[i-1][j-1];
}
}
}
LL C(LL n,LL m) {
if(m>n) return 0;
return c[n][m];
}
int n,m;
int main()
{
Init();
while(~scanf("%d %d",&n,&m)) {
n++,m++;
LL ans = C(n*m,3); ans = ans-C(n,3)*m-C(m,3)*n;
for(int i = 1;i<n;i++) {
for(int j = 1;j<m;j++) {
int g = __gcd(i,j)+1;
ans-=((g-2)*(n-i)*(m-j)*2);
}
}
printf("%lld\n",ans);
}
return 0;
}