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;
代码