zoukankan      html  css  js  c++  java
  • HDU6682 Rikka with Mista

    题意

    给出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
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    kafka注册异常
    Android基于XMPP Smack Openfire下学习开发IM(五)连接断开重连
    openfire维持在线状态,监听消息
    openfire ping的smack解决方案(维持在线状态)
    openfire聊天记录插件
    openfire 发送 接受 注册 广播 好友列表 在线状态
    maven仓库中心mirrors配置多个下载中心(执行最快的镜像)
    开发openfire 消息拦截器插件PacketInterceptor
    Openfire注册流程代码分析
    linux centOS6 nexus 开启自动启动
  • 原文地址:https://www.cnblogs.com/zhanggengchen/p/11406422.html
Copyright © 2011-2022 走看看