2019HDU多校赛第九场C、Rikka with Mista(折半搜索+two pointers)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/C20180602_csq/article/details/100180721

Rikka with Mista

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 941    Accepted Submission(s): 255


 

Problem Description

Rikka is a fervent fan of JoJo's Bizarre Adventure. As the last episode of Golden Wind has been aired, Rikka, with the help of Yuta, sets up this problem to express the love to Mista.

Mista's lucky number is 4. Today, Mista wants to test his luck with n magic cards: For each card, there is a non-negative integer on each side. The two numbers on the ith card are wi and 0.

Firstly, Mista puts these n cards to table one by one. For each card, the probability of the wi side to be upward is 12, and these probabilities are independent with each other. As a result, there are n integers on the table. Mista then sums up all these integers and counts the number of 4s in the decimal representation of this sum: He uses this result to measure his luckiness.

Since it's possible for each side of each card to be upward, there are 2n possible states in total. You are required to calculate the sum of the results for all these situations.

 

Input

The first line of the input contains a single integer T(4≤T≤4), the number of test cases.

For each test case, the first line contains a single integer n(4≤n≤40), the number of the cards.

The second line contains n integers w1,…,wn(4≤wi≤44444444), the positive numbers on the cards.

Output

For each test case, output a single line with a single integer, the answer.

Hint

There are 44 4s in the sample input. Mista would like this sample input.

In the first test case, there is 1 state with the sum equal to 0; 4 states with the sum equal to 4; 6 states with the sum equal to 8; 4 states with the sum equal to 12 and 1state with the sum equal to 16.

Therefore, there are only 4 situations with the result equal to 1 while on other cases, the result is 0. So the answer should be 4.

扫描二维码关注公众号,回复: 7640186 查看本文章

Sample Input

4

4

4 4 4 4

4

4 4 44 44

4

4 44 44 4444

4

444 44444 44444 4444444

Sample Output

4

10

24

38

题意

有n个数(n<=40),每个数在1~44444444的范围内,求所有选数方案的数字和中4的总数

题解

首先想到分别统计每一位上的4的个数

发现数据范围n<=40,可以折半搜索

于是我们就可以把前面编号1~20的数分为一组,后面编号21~40的数分为一组

把前面一组的所有子集的数字和预处理出来,后面一组也一样

于是问题就转化为:

前一半选一个和,后一半选一个和,两个加起来所得的数的4的个数

因为要分位统计,所以我们可以让所有的和都mod10^{i}之后进行排序,用two pointers(利用单调性)扫一遍统计答案

(注意统计答案的时候要分进位和不进位两种情况)

但是这样会T

然后就有了一个巧妙的优化:从下向上依次枚举每一位,同时对这些和进行基数排序(因为低位是已经排好了的,所以只用排当前位)

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1100005
#define LL long long
struct node{
	int c;
	LL x,y;
}a[N],b[N],tmp[N];
LL p[15],w[45],ans;
int tong[15];
int na,nb,lim;
void dfs(int i,LL sum,int flg)
{
	if(i>lim){
		if(flg==1)b[++nb].x=sum;
		else a[++na].x=sum;
		return;
	}
	dfs(i+1,sum+w[i],flg);
	dfs(i+1,sum,flg);
}
int main()
{
	int T,n,i,j,l,r;
	p[0]=1;
	for(i=1;i<=10;i++)
		p[i]=10ll*p[i-1];
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(i=1;i<=n;i++)
			scanf("%lld",&w[i]);
		na=nb=0;
		ans=0;
		lim=n>>1;dfs(1,0,0);
		lim=n;dfs((n>>1)+1,0,1);
		for(i=1;i<=na;i++)a[i].y=0;
		for(i=1;i<=nb;i++)b[i].y=0;
		for(i=0;i<=9;i++){
			for(j=0;j<=9;j++)tong[j]=0;//巧妙的基排
			for(j=1;j<=na;j++)a[j].c=(a[j].x/p[i])%10,tong[a[j].c]++;
			for(j=1;j<=9;j++)tong[j]+=tong[j-1];
			for(j=na;j>=1;j--)tmp[tong[a[j].c]--]=a[j];
			for(j=1;j<=na;j++)a[j]=tmp[j],a[j].y+=1ll*p[i]*a[j].c;
			
			for(j=0;j<=9;j++)tong[j]=0;
			for(j=1;j<=nb;j++)b[j].c=(b[j].x/p[i])%10,tong[b[j].c]++;
			for(j=1;j<=9;j++)tong[j]+=tong[j-1];
			for(j=nb;j>=1;j--)tmp[tong[b[j].c]--]=b[j];
			for(j=1;j<=nb;j++)b[j]=tmp[j],b[j].y+=1ll*p[i]*b[j].c;
			
			l=0;r=0;
			for(j=na;j>=1;j--){//进位
				while(r<nb&&b[r+1].y+a[j].y<5ll*p[i])r++;
				while(l<r&&b[l+1].y+a[j].y<4ll*p[i])l++;
				ans+=1ll*(r-l);
			}
			l=0;r=0;
			for(j=na;j>=1;j--){//不进位
				while(r<nb&&b[r+1].y+a[j].y<15ll*p[i])r++;
				while(l<r&&b[l+1].y+a[j].y<14ll*p[i])l++;
				ans+=1ll*(r-l);
			}
		}
		printf("%lld\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/C20180602_csq/article/details/100180721