8.24 学习
上午对之前的题目进行了补充与完善,将清理题单,感悟:
数位DP:
在做的时候一定要注意前面项与后面项的特判如
P13085 [SCOI2009] windy 数(加强版):https://www.luogu.com.cn/problem/P13085#submit
不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数
由上可以看出solve(a)求出1~a之间cloudy数数量时应注意前后项
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
ull f[20][10], power[20];
ull a, b;
void init() {
power[0] = 1;
for(int i = 1; i <= 19; i++)
power[i] = power[i-1] * 10;
for(int i = 0; i <= 9; i++)
f[1][i] = 1;
for(int i = 2; i <= 19; i++)
for(int j = 0; j <= 9; j++)
for(int k = 0; k <= 9; k++)
if(abs(j - k) >= 2)
f[i][j] += f[i-1][k];
}
ull solve(ull x) {
if(x == 0) return 0;
int w = 0;
while(power[w] <= x) w++;
ull ans = 0;
for(int i = 1; i < w; i++)
for(int j = 1; j <= 9; j++)
ans += f[i][j];
int y = x / power[w-1];
for(int j = 1; j < y; j++)
ans += f[w][j];
int pre = y;
x %= power[w-1];
for(int i = w-1; i >= 1; i--) {
y = x / power[i-1];
for(int j = 0; j < y; j++) {
if(abs(j - pre) >= 2) {
ans += f[i][j];//!!!!!!!就是这里,要注意要单独拿出来判断后累加
}
}
if(abs(pre - y) < 2) break;
pre = y;
x %= power[i-1];
}
return ans;
}
int main() {
cin >> a >> b;
init();
ull ans = solve(b + 1) - solve(a);
cout << ans << endl;
return 0;
}
状压DP:状压DP感觉不少时候其实也可以用随机化以及做出来后看题解的重要性
P1441砝码称重:https://www.luogu.com.cn/problem/P1441
P1441 砝码称重
题目描述
现有 $n$ 个砝码,重量分别为 $a_i$,在去掉 $m$ 个砝码后,问最多能称量出多少不同的重量(不包括 $0$)。
请注意,砝码只能放在其中一边。
这道题我第一反应是先从1~1<<n 枚举,找到所有恰好有n-m个砝码的情况,然后再通过第i个砝码用不用+hash的方式来判断,WA了。
换了个思路设计依旧使用1~1<<n枚举出所有符合的情况,然后对于每个符合的情况,不局限于状压,感觉用01背包更合适。
f[i][j]的意思是:当前称出总重量i是用j及以前的砝码是否可行,可行为1,不可行为j
状态转移方程为: f[i][j]=f[i-a[i]][j-1];
做完后看了一眼题解,发现了很多新奇的想法。
1.寻找删m个方案也可以用DFS+剪枝,优化的好的甚至比位运算递加还快。
2.bitset好像在位运算中比较有用,明天学一下。
3.居然还可以用随机化,思想是随机的在创建一个b数组中放入m个1,表示去掉的砝码,然后直接对剩下的砝码进行搜索。
4.我的做法还可以通过滚动数组不断更新上界来优化。
下午:打了场梦熊周赛J组,

浙公网安备 33010602011771号