码迷,mamicode.com
首页 > 其他好文 > 详细

HDU6682 Rikka with Mista

时间:2019-08-25 00:55:38      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:tag   space   can   turn   its   pid   for   amp   根据   

题意

给出n(<=40)个数,每个数范围1到44444444,选出一些数求和,求\(2^n\)种选数方案中所求的和含有多少个4。
题目链接

思路

根据数据范围可以判断是折半搜索,两次搜索得出前一半与后一半能够得出的数,分别储存在a,b两个数组,合并时按位枚举每一位有多少个4。如果我们计算第i位,则按照\(x%10^{i+1}\)将a,b排序。对于a[i],第一种情况\(4*10^{i}\)<=a[i]+b[i]<\(5*10^{i}\)是一段区间,第二种情况\(14*10^{i}\)<=a[i]+b[i]<\(15*10^{i}\)也是一段区间。我们用滑动窗口对两种情况分别计数。每次排序要用基数排序,不然可能会T。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 3000000+10;

struct node
{
    LL x,y;
    int c;
};

int n,na,nb;
node a[maxn],b[maxn],tmp[maxn];
LL p[25];
int X[maxn],cnt[25];
LL ans;

void dfs(int x,int N,LL sum,bool tag)
{
    if (x==N+1)
    {
        if (!tag) a[++na].x=sum; else b[++nb].x=sum;
        return;
    }
    dfs(x+1,N,sum,tag);
    dfs(x+1,N,sum+(LL)X[x],tag);
}

int main()
{
    p[0]=1;
    for (int i=1;i<=11;i++) p[i]=p[i-1]*10LL;
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&X[i]);
        int mid=(n+1)>>1;
        na=nb=0;
        ans=0;
        dfs(1,mid,0,0);
        dfs(mid+1,n,0,1);
        for (int i=1;i<=na;i++) a[i].y=0;
        for (int i=1;i<=nb;i++) b[i].y=0;
        for (int o=0;o<=9;o++)
        {
            for (int i=0;i<=9;i++) cnt[i]=0;
            for (int i=1;i<=na;i++) a[i].c=(a[i].x/p[o])%10,cnt[a[i].c]++;
            for (int i=1;i<=9;i++) cnt[i]=cnt[i-1]+cnt[i];
            for (int i=na;i>=1;i--) tmp[cnt[a[i].c]--]=a[i];
            for (int i=1;i<=na;i++) a[i]=tmp[i],a[i].y+=p[o]*(LL)a[i].c;

            for (int i=0;i<=9;i++) cnt[i]=0;
            for (int i=1;i<=nb;i++) b[i].c=(b[i].x/p[o])%10,cnt[b[i].c]++;
            for (int i=1;i<=9;i++) cnt[i]=cnt[i-1]+cnt[i];
            for (int i=nb;i>=1;i--) tmp[cnt[b[i].c]--]=b[i];
            for (int i=1;i<=nb;i++) b[i]=tmp[i],b[i].y+=p[o]*(LL)b[i].c;

            int l=0,r=0;
            LL L,R;
            L=p[o]*4LL; R=p[o]*5LL;
            for (int i=na;i>=1;i--)
            {
                while (r+1<=nb&&b[r+1].y+a[i].y<R) r++;
                while (l+1<=r&&b[l+1].y+a[i].y<L) l++;
                ans+=(LL)(r-l);
            }
            L=p[o]*14LL; R=p[o]*15LL;
            for (int i=na;i>=1;i--)
            {
                while (r+1<=nb&&b[r+1].y+a[i].y<R) r++;
                while (l+1<=r&&b[l+1].y+a[i].y<L) l++;
                ans+=(LL)(r-l);
            }

        }
        printf("%lld\n",ans);
    }
    return 0;
}

HDU6682 Rikka with Mista

标签:tag   space   can   turn   its   pid   for   amp   根据   

原文地址:https://www.cnblogs.com/zhanggengchen/p/11406422.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!