• 【Henu ACM Round#18 E】Anya and Cubes


    【链接】 我是链接,点我呀:)
    【题意】

    在这里输入题意

    【题解】

    每个数字有3种选择。 1.选中它。 2.选中它且加阶乘符号 3.不选中它(即计算和的时候不考虑它)

    如果我们直接暴力写的话复杂度是(3^{25})
    寻求优化。

    我们可以用Meet-in-the-middle这个方法。
    先求出1..n/2这些数字的组合方式。
    用map<ll,ll> dic[25]来存它们的和。
    dic[i][j]表示前n/2个数字中选了i个【2】状态的数字,和为j的方案数。
    则我们再穷举n/2+1..n这些数字的选择情况。
    得到了和sum以及【2】状态的数字个数cnt之后。
    答案累加(∑_0^{k-cnt}dic[i][m-sum])
    这样复杂度就是(O(3^{12}))级别的了。
    完全可以接受了
    (n=1的时候,n/2等于0,如果你的dfs里面写的条件是now==n/2,应该把它改为now>=n/2,如果不这么改的话,dic[0][0]=1这个会漏掉,
    然后右半边就可能会漏解了)

    【代码】

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int N = 1e6;
    const int M = 25;
    const int MM = 200e4;
    
    int n,k,a[M+10],bo[M+10],tt;
    ll pre[M+10],m,ans;
    vector<ll>b[M+1];
    
    int get_num(int cnt,ll x){
        int l = 0,r = b[cnt].size()-1,temp1=-1,temp2=-1;
    
        while (l <= r){
            int mid = (l+r)>>1;
            if (x<=b[cnt][mid]){
                temp1 = mid;
                r = mid-1;
            }else l = mid+1;
        }
    
        l = 0,r = b[cnt].size()-1;
        while (l <= r){
            int mid = (l+r)>>1;
            if (x>=b[cnt][mid]){
                temp2 = mid;
                l = mid+1;
            }else r = mid-1;
        }
    
        if (temp1==-1 || temp2 ==-1 ||  b[cnt][temp1]!=x) return 0;
        else return temp2-temp1+1;
    }
    
    void dfs(int now,int ope){
        int st,en;
            if (ope==1)
                st = 1,en = n/2;
            else
                st = n/2+1,en = n;
        if (now>=en+1){
            ll sum = 0;
            int cnt = 0;
            for (int i = st;i <= en;i++){
                if (bo[i]==0) continue;
                if (bo[i]==2){
                    if (a[i]>=19) return;
                    sum+=pre[a[i]];
                    cnt++;
                }else sum+=a[i];
            }
            if (sum > m) return;
            if (ope==1){
                b[cnt].push_back(sum);
            }else{
                for (int i = 0;i <= k-cnt;i++) {
                    ans+=get_num(i,m-sum);
                }
            }
            return;
        }
    
        bo[now] = 0;
        dfs(now+1,ope);
    
        bo[now] = 1;
        dfs(now+1,ope);
    
        bo[now] = 2;
        dfs(now+1,ope);
    }
    
    int main()
    {
        #ifdef LOCAL_DEFINE
            freopen("rush_in.txt","r",stdin);
        #endif
       ios::sync_with_stdio(0),cin.tie(0);
        pre[0] = 1;
        for (int i = 1; ;i++){
            pre[i] = pre[i-1]*i;
            if (pre[i]>1e16+10) break;
        }
        cin >> n >> k >> m;
        for (int i = 1;i <= n;i++) cin >> a[i];
        dfs(1,1);
        for (int i = 0;i <= k;i++) sort(b[i].begin(),b[i].end());
        dfs(n/2+1,2);
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    CDQ分治
    K-th Number POJ
    A * B Problem Plus HDU
    Prime Test POJ
    数据结构
    FFT
    mysql查询出相同数据出现的次数,统计相同值的数量
    Laravel 清空配置缓存
    php7 数据导出Excel office 2011中文乱码问题
    PHP file_put_contents函数数据导出csv文件,屏幕字符串逗号分隔符
  • 原文地址:https://www.cnblogs.com/AWCXV/p/8377768.html
Copyright © 2020-2023  润新知