【组合 数学】codeforces C. Do you want a date?

codeforces.com/contest/810/problem/C

【题意】

给定一个集合A,求

输入:

【思路】

基数为n的集合有2^n-1个非空子集。

首先n个数要从小到大排序,枚举最后的集合中最大和最小的元素是a[i]和a[j](i< j); 
则f值是a[j]-a[i]的集合有2^(j-i-1)个; 然后答案+=(a[j]a[i])*2^(j-i-1);

这样时间复杂度是O(n^2)。

我们可以把各项组合一下,把2^i提取出来。

比如考虑系数为 
2^1的 
必然是 
a[3]-a[1] 
a[4]-a[2] 
a[5]-a[3] 
… 
a[n]-a[n-2] 
=sum[n]-sum[i+1]-sum[n-i-1];

sum[i]是a[i]的前缀和。

这样对于[0,n-2]枚举2^i,时间复杂度是O(n),加上排序,总的时间复杂度是O(nlogn)

【注意】

sum[i]是取余后的结果,所以sum[n]-sum[i+1]-sum[n-i-1]可能是负数,要(+mod)%mod

【Accepted】

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <cmath>
 4 #include <vector>
 5 #include <algorithm>
 6 #include <set>
 7 #include <map>
 8 #include <queue>
 9 #include <deque>
10 #include <stack>
11 #include <string>
12 #include <bitset>
13 #include <ctime>
14 #include<algorithm>
15 #include<cstring>
16 using namespace std;
17 typedef long long ll;
18 const int maxn=3e5+3;
19 const ll mod=1e9+7;
20 int a[maxn];
21 int n;
22 ll sum[maxn];
23 ll two[maxn];
24 
25 void Init()
26 {
27     two[0]=1;
28     for(int i=1;i<=maxn;i++)
29     {
30         two[i]=(two[i-1]*2)%mod;
31     }
32 }
33 int main()
34 {
35     Init();
36     while(~scanf("%d",&n))
37     {
38         memset(sum,0,sizeof(sum));
39         for(int i=1;i<=n;i++)
40         {
41             scanf("%d",&a[i]);
42         }
43         sort(a+1,a+n+1);
44         for(int i=1;i<=n;i++)
45         {
46             
47             sum[i]=(sum[i-1]+(ll)a[i])%mod;
48         }
49         ll ans=0;
50         for(int i=0;i<=n-2;i++)
51         {
52             ans=(ans+two[i]*(sum[n]-sum[n-i-1]-sum[i+1]+mod)%mod)%mod;
53         }
54         cout<<ans<<endl;        
55     }
56     return 0;
57 }
View Code

 

posted @ 2017-06-02 21:33  shulin15  阅读(395)  评论(0编辑  收藏  举报