有一个数列A已知对于所有的A[i]都是1~n的自然数,并且知道对于一些A[i]不能取哪些值,我们定义一个数列的积为该数列所有元素的乘积,要求你求出所有可能的数列的积的和 mod 1000000007的值;
--by洛谷;
http://daniu.luogu.org/problem/show?pid=2220
简单题?呵呵
首先,她有个公式
我们先假设k=0;
ai为a位的可能;bi为b位的可能;ci为c位的可能...
则:
a1*b1*c1+a1*b1*c2+a1*b2*c1+a1*b2*c2+a2*b1*c1+a2*b1*c2+a2*b2*c1+a2*b2*c2;
你提公因式嘛;
a1*(b1*c1+b1*c2+b2*c1+b2*c2)+a2*(b1*c1+b1*c2+b2*c1+b2*c2);
再提
a1*[b1*(c1+c2)+b2*(c1+c2)]+a2*[b1*(c1+c2)+b2*(c1+c2)];
a1*(b1+b2)*(c1+c2)+a2*(b1+b2)*(c1+c2);
(a1+a2)*(b1+b2)*(c1+c2);
再通过k的存在,对每位的可能减zi;
(a1+a2-z1)*(b1+b2-z2)*(c1+c2-z3);
然后每一位在k=0一样,即a1+a2=b1+b2=c1+c2=sum(n);
(sum(n)-z1)*(sum(n)-z2)*(sum(n)-z3);
所以,这叫简单题?
就想预处理sum(n)然后O(n)乘,每次记得减z;
然而O(n)也过不了——n=1e9。。。
所以,这叫简单题?
但是我们发现,k比较小,1e5;
所以有限制的位置,小于等于1e5;
我们可以先算她们,然后剩下的写一个快速幂;
时间效率O(klogk+k+log(n-k));
(因为有个sort);
代码如下:
1 #include<cstdio> 2 #include<algorithm> 3 #define mod 1000000007 4 using namespace std; 5 struct ss 6 { 7 int x,y; 8 }a[100001]; 9 long long b[100001]; 10 11 bool cmp(ss a,ss b) 12 { 13 if(a.x==b.x) 14 return a.y<b.y; 15 return a.x<b.x; 16 } 17 long long sqr(long long ,int ); 18 19 int main() 20 { 21 int n,m,k; 22 long long sz1=0; 23 long long ans=1; 24 int i,j,l; 25 scanf("%d%d%d",&n,&m,&k); 26 sz1=(long long)n*(n+1)/2%mod; 27 for(i=1;i<=k;i++) 28 scanf("%d%d",&a[i].x,&a[i].y); 29 sort(a+1,a+k+1,cmp); 30 j=0; 31 for(i=1;i<=k;i++) 32 { 33 if(a[i].x!=a[i-1].x) 34 b[++j]=a[i].y; 35 else 36 if(a[i].y!=a[i-1].y) 37 b[j]=(b[j]+a[i].y)%mod; 38 } 39 for(i=1;i<=j;i++) 40 ans=(ans*(sz1-b[i]+mod))%mod; 41 m=m-j; 42 ans=(ans*sqr(sz1,m))%mod; 43 printf("%lld",ans); 44 return 0; 45 } 46 47 long long sqr(long long sz,int m) 48 { 49 long long ans=1; 50 while(m) 51 { 52 if(m&1) 53 ans=(ans*sz)%mod; 54 sz=(sz*sz)%mod; 55 m=m>>1; 56 } 57 return ans; 58 }
祝AC哟;