奇怪的道路

 

DeepinC的题解

考场AC nb%%%%%%%%%%%%%%%%%%

2019/4/27
Day1  T3 奇怪的道路


step1:复杂度分析

1<= n <= 30, 0 <= m <= 30, 1 <= K <= 8.
按照习惯,正解复杂度一般在1e6-1e8级别
而且往往复杂度关系最大的就是最小的那个数
对,抓住那个k=8打
所以说先蒙个复杂度
O(mnk)?太小
O(mn*2^k)这个差不多
所以试试状压?


step2:算法

算法一:
其实看到这么小的数据范围应该也能 <感受一下> 状压的气息吧
[任何一个城市都与恰好偶数条道路相连(0也被认为是偶数)]
奇数偶数?可以用0,1,两种状态表示,这很状压,这非常状压
设dp[n][m][state]表示已经考虑了n个城市,m条道路,所有城市状态为state时的情况数
如果你把n和p连起来,n-k<=p<n      (pow[i]表示2的i次方)

    dp[n][m][state]+=dp[n][m-1][state^pow[n]^pow[p]];
异或超棒的,当你连上一条路时,两个端点已经连上的路原来是奇数的就变成偶数,偶数就变成奇数
题库里内存128M,考试时内存256M,state太占内存,大概能处理n=15,一半分

算法二:(优化)
我说过那个最小的k是突破口吧?但是用上了吗?
根据复杂度分析,如果把那个2^n替换成2^k就可以了
那么就要把state的位数变成k,仔细一看,刚好合适
那么state的含义稍微一变:最后k座城市的状态
<交线牛逼法>很好啊,因为第i座城市的状态转移只与最后k座城市有关
<NOI2019 Day2 T1 mentor:中国好码农>ing...
码出来的时候,忽然发现一个问题,我没考虑当前城市的情况,所以state的大小其实是2^(k+1)
<王鹤松式>没关系没关系,复杂度更接近上限了,正确的可能性更高了(玄学信仰)
状态转移的式子稍微一改
    dp[n][m][state]+=dp[n][m-1][state^1^pow[n-p]];
而且因为state的表示范围在变化,所以对于每个n,dp值都需要特殊转移
    dp[n][m][(state<<1)&(pow[k+1]-1)]+=dp[n-1][m][state];
dp[n][m][0]即为答案

算法三:(无关紧要的优化)
时间小优化:
    我是个听学长话的乖孩子。。。。。。
    他说过,取模超级慢的是嘛?
    怎么避免取模呢?减法优于取模,判断优于计算
    inline long long mod(long long k){return k>=1000000007?k-1000000007:k;}
    因为代码里只存在加法,所以计算结果不会超过1000000007*2,减去一个1000000007就行了
空间大优化:
    为什么只有256M啊?NOI还有5G呢
    可见,dp式子只从n-1转移到n
    滚动数组!棒!
    式子再稍微一改
        dp[i&1][j][s]=mod(dp[i&1][j][s]+dp[i&1][j-1][s^1^pow[i-p]]);
        dp[(i&1)^1][j][s<<1]=dp[i&1][j];
    滚起来别忘了清空数组
        dp[i&1][j][s]=0;

编号     题目     状态     分数     总时间     内存     代码 / 答案文件     提交者     提交时间
#57153     
#C. 奇怪的道路
    Accepted     100     67 ms     616 KiB     C++11 / 754 B     DeepinC (吴迪)     2019-04-27 21:46:34

20个测试点,时间还不错
k=8的话目测可以处理m=n=300;

代码

 

posted @ 2019-07-30 10:35  znsbc  阅读(183)  评论(0编辑  收藏  举报