2019 Multi-University Training Contest 9 Rikka with Mista (折半搜索+桶排)

Rikka with Mista

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


 

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.

 

 

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

 

 

Source

2019 Multi-University Training Contest 9

 题目大意:给出了40个数,每个数选或者不选,问所有可能的和中数字4出现的次数是多少。

解题思路:首先想到用折半搜索处理出前后半部分所有可能的和。然后就是如何统计和中4出现的次数。

我们可以一位一位的考虑该为4的所有情况,然后相加。

对于第i位,我们只考虑后缀的和,即后i位的和,然后枚举左边的和,二分找右边合法的区间。

这里合法的区间我们要考虑进位和不进位如2xx+2xx=4xx ,7xx+7xx=14xx。

但是nlogn的排序会超时。

由于我们每次只是对后缀的排序,所以我们可以用桶排序优化,做到o(n)。

标程的实现非常简洁。就是枚举所所有能够产生4的情况 

比如 0 4 ,1 3 ,2 2,3 1,6 8,等等。。。

比如当前计算到了第i位,我们分为两种情况计算,分别是后i-1位有进位和后i-1位没有进位。

第一种情况就是上述举例,后者的话就是 枚举当前第i位相加mod10==3的情况(因为有进位)。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mp(x,y) make_pair(x,y)
typedef pair<ll,ll>pii;
#define pb(x) push_back(x)
#define fir first
#define sec second

vector<pii>x,y;
const int N = 1<<20+5;
int a[55];

vector<pii>A[10],B[10];

void dfs(int pos, int len, ll sum, vector<pii> &tmp)
{
    if(pos>len)
    {
        tmp.pb(mp(sum,0));
        return ;
    }
    dfs(pos+1,len,sum,tmp);
    dfs(pos+1,len,sum+a[pos],tmp);
}

ll get0(vector<pii> &a, vector<pii> &b, ll base)
{
    int r=b.size()-1;
    ll ans=0;
    for(int i=0; i<a.size(); i++)
    {
        while(r>=0 && a[i].sec+b[r].sec >= base) r--;
        ans += r+1;
    }
    return ans;
}

ll get1(vector<pii> &a, vector<pii> &b, ll base)
{
    int l=0;
    ll ans=0;
    int sz=b.size();
    for(int i=a.size()-1; i>=0; i--)
    {
        while(l<sz && a[i].sec+b[l].sec<base) l++;
        ans += (sz-l);
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;scanf("%d",&n);

        x.clear(),y.clear();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int mid=n/2;
        dfs(1,mid,0,x);
        dfs(mid+1,n,0,y);


        ll base=1;
        ll ans = 0;
        for(int tt=1; tt<=11; tt++)
        {
            for(int i=0; i<10; i++)  A[i].clear(),B[i].clear();

            for(int i=0; i<x.size(); i++) A[x[i].fir%10].pb(mp(x[i].fir/10,x[i].sec));
            for(int i=0; i<y.size(); i++) B[y[i].fir%10].pb(mp(y[i].fir/10,y[i].sec));

            for(int i=0; i<10; i++)
            {
                int k1 = (14 - i) % 10, k2 = (13-i)%10;
                ans+= get0(A[i],B[k1],base) + get1(A[i],B[k2],base);
            }

            int now=0;
            for(int i=0; i<10; i++)
            {
                ll tmp=i*base;
                for(int j=0; j<A[i].size(); j++)
                {
                    x[now++]=(mp(A[i][j].fir,A[i][j].sec+tmp));
                }
            }
            now=0;
            for(int i=0; i<10; i++)
            {
                ll tmp=i*base;
                for(int j=0; j<B[i].size(); j++)
                {
                    y[now++]=(mp(B[i][j].fir,B[i][j].sec+tmp));
                }
            }
            base*=10;
        }
        printf("%lld\n",ans);
    }
}
/*
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值