HOJ 13845 Atomic Computer有向无环图的动态规划

考虑任意一个数字,任何一个都会有奇怪的。。性质,就是一个可以保证不重复的方案——直接简单粗暴的最高位加数字。。于是,如同上面的那个题:+1、-1、0

但是考虑到65536KB的标准内存限制,会得出一个奇怪的性质,那就是。。。这题可以先大表之后对内存做奇怪的优化——前十位开小一点,后十位开大一点。之前计算时间复杂度的时候是1e6*20这种按照全部数组空间扫一发的方式进行计算,但是后面发现,这种方式其实是没必要,观察可以发现,实际上这道题不论怎么做奇怪的计算都是实质上的——也就是穷举SUM(2^k)。于是。。。。。。全部复杂度大概就被强行限制到了1e6的规模。之后进行任意一种方式查询即可。。。。查询复杂度是O(1)

但是最开始的时候踩了个坑——对于数字X应该怎么做才能够将他给他多加一位还能够保证不重复呢?或者说应该把新的数字加到哪里呢?最开始想到的是末尾,但是看上去末尾不够好。。。于是考虑往中间加,但是明显的限制是——排列组合的个数无论如何都不可能、也不能够,比3^N更多。于是。。。我们可以考虑愉快的吧新的位数加到想象中的二进制串串的最最前面。并且这种做法的直接好处是,可以“制度性的保证不出现重复”。。

这题当时在做的时候打了好长好长的表,试图进行相关对比。。然而。。。。有向无环图的动态规划问题。。。

当然题目中自带的坑差点把我误导了——他给的查询数字异常的大,之前以为实际达到的数字也是那么大来着。。。但是很显然不是,因为最大值的限制是2^N这个尺寸的限制。
于是在这个问题的处理上需要对最大值情况进行特殊判断。

AC代码:

#include<iostream>
#include<math.h>
using namespace std;

long long dic[23];
int dp1[3048][11];
int dp[1050000][10];

void init()
{
    long long kk=1;
    for(int i=0;i<23;++i)
    {
        dic[i]=kk;
        kk*=2;
    }dp1[0][0]=1;
    
//    cout<<dic[20]<<endl;
    for(int i=0;i<11;++i)
    {
        for(int j=0;j<dic[i];++j)
        {
            int val=j;
            dp1[val+dic[i]][i+1]+=dp1[j][i];
            dp1[val][i+1]+=dp1[j][i];
            dp1[abs(val-dic[i])][i+1]+=dp1[j][i];

        }
    }
    
    for(int j=0;j<=dic[11];++j)
        {
            dp[j][0]=dp1[j][11];
        }
    for(int i=11;i<20;++i)
    {
//        cout<<dic[i]<<endl;
        for(int j=0;j<dic[i];++j)
        {
            int val=j;
            dp[val+dic[i]][i+1-11]+=dp[j][i-11];
            dp[val][i+1-11]+=dp[j][i-11];
            dp[abs(val-dic[i])][i+1-11]+=dp[j][i-11];

        }
    }
}

int main()
{
    cin.sync_with_stdio(false);
//    freopen("indata.in","r",stdin);
//    freopen("out.txt","w",stdout);
//    cout<<pow(2,20)<<endl;
    init();
    int t;
    cin>>t;//cout<<t<<endl;
    while(t--)
    {
        long long a,b;
        cin>>a>>b;
        if(b<11)
        {    
            if(a==0)
            {
                cout<<1<<endl;
                continue;
            }
            if(abs(a)>=dic[b])cout<<0<<endl;
            else cout<<dp1[abs(a)][b]/2<<endl;
        }else
        {
            if(a==0)
            {
                cout<<1<<endl;
                continue;
            }
            if(abs(a)>=dic[b])cout<<0<<endl;
            else cout<<dp[abs(a)][b-11]/2<<endl;
        }
    }
    return 0; 
}

数据生成器:

#include<bits/stdc++.h>
using namespace std;
int aa=8;
int main()
{
        freopen("indata.in","w",stdout);
        
        long long bb=-pow(2,aa)+1;
        cout<<(long long)pow(2,aa+1)-1<<endl;
        while(bb<pow(2,aa))cout<<bb++<<"   "<<aa<<endl;

}

检查的代码:

#include<bits/stdc++.h>
using namespace std;

long long aa[23];
void init()
{
    long long k=1;
    for(int i=0;i<23;++i)
    {
        aa[i]=k;
        k*=3;
    }
}

int main()
{
    init();
        freopen("out.txt","r",stdin);
    long long a,summ=0;
    while(cin>>a)summ+=a;
    cout<<summ<<endl;
    cout<<aa[lower_bound(aa,aa+23,summ)-aa];
}
原文地址:https://www.cnblogs.com/rikka/p/7450115.html