Problem A. Math Encoder Google Kickstart Round B 2017

这一题数组K_i是排好序的是一个很有用的hint。某一个子集对应的difference只由最大和最小的两个数决定,所以只要考虑任意两个数K_i,K_j可以作为多少个子集的最大最小数即可。

size=1的子集对结果贡献是0,不用考虑。对于升序数组a,b,c,d,如果a,d是最大最小的数,那么对应的集合有{a,d},{a,b,d},{a,c,d},{a,b,c,d},size分别为2,3,3,4。对应的就是a与d之间选择0 or 1 or 2个元素组成一个新集合。集合总数就是在a,d之间的元素{b,c}对应的集合总数,namely,C(2,0)+C(2,1)+C(2,2)。

对于两个数K_i,K_j,对应的贡献就是(K_j-K_i)*(sum_{l=0}^{j-i-1} C(j-i-1,l))=(K_j-K_i)*2^{j-i-1}。

我居然用前缀和来求(K_j-K_i),真是多此一举。><

ans就是对于所有的(i,j), j>i, 将其贡献的值加起来。

2^{j-i-1}可以预处理求得。因为有溢出问题,所以要循环求2^n,每次*2之后都要%mod。

另外,公式里有两个相乘的项,因为可能是1e9*1e9这种数量级,直接用int存会溢出。因为这个原因大数据incorrrect了,最后把所有的变量都改成long long才通过。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

//Kickstart 2017 Problem A. Math Encoder
int T;
const int maxn=10010;
int N;
long long arr[maxn];
long long gap[maxn];
long long pregapsum[maxn];
long long twopow[maxn];
const long long mod=1000000007;
long long ans=0;
void calpow()
{
    twopow[0]=1;
    for(int i=1;i

你可能感兴趣的:(Problem A. Math Encoder Google Kickstart Round B 2017)