JZYZ作业好题

0|1文章目录

1|0敲砖块

在这里插入图片描述
首先把砖块向左对齐, 这样选择第 ( i , j ) (i,j) (i,j)块的前提是第 ( i − 1 , j ) , ( i − 1 , j + 1 ) (i - 1, j),(i - 1,j + 1) (i1,j),(i1,j+1)被选

满足敲掉的砖块总代价最大,显然是动态规划,接下来我们思考如何设计状态

按照正常的思路应当是 f [ i ] [ j ] f[i][j] f[i][j]表示到第 i i i行一共选择 j j j个的最大价值,但是选择第 i i i行的每一个所对应的 f [ i − 1 ] [ ] f[i-1][] f[i1][]的状态和选择都不一样,且很不好维护最值(貌似还要容斥)

我们尝试更改状态,思考敲掉一个砖块需要哪些被敲掉

在这里插入图片描述
若敲掉蓝色点 ( i , j ) (i,j) (i,j),显然第 j j j至少敲掉前 i i i个, 第 j + 1 j + 1 j+1列至少敲掉前 i − 1 i - 1 i1个,依次类推

所以我们发现,如果按列考虑,不仅可以保证一定可以敲掉,而且统计答案非常方便

设计状态 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示第 i i i列,敲掉前 j j j个且一共敲掉前 k k k的最大价值

f [ i ] [ j ] [ k ] = m a x ( f [ i + 1 ] [ s ] [ k − j ] + s u m [ j ] [ i ] , s ≥ j − 1 ) f[i][j][k]= max(f[i+1][s][k-j]+sum[j][i],s\ge j-1) f[i][j][k]=max(f[i+1][s][kj]+sum[j][i],sj1) s u m [ j ] [ i ] sum[j][i] sum[j][i]表示第j列取前 i i i个的价值

复杂度为 n 5 n^5 n5,但是跑不满,应该除以一个至少为4的常数,所以能跑过,不过枚举 s s s可以优化掉,这样就变成 n 4 n^4 n4

#include<bits/stdc++.h> //竖着看 using namespace std; #define LL long long const int MAX = 55; int f[MAX][MAX][MAX * MAX]; //先i列,第i列选j个,总数为 k int n, m, a[MAX][MAX], Num[MAX]; int sum[MAX][MAX], ans = 0; int main() { freopen("brike.in","r",stdin); freopen("brike.out","w",stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) for(int j = 1; j <= (n - i + 1); j++) { scanf("%d", &a[i][j]); sum[i][j] = sum[i - 1][j]; sum[i][j] += a[i][j]; } for(int i = 1; i <= n; i++) Num[i] = Num[i - 1] + i; for(int i = n; i >= 1; i--) { //第i列 for(int j = 0; j <= (n - i + 1); j++) { //第i列选j个 for(int k = Num[j]; k <= m; k++) { //选择总数 for(int s = j - 1; s <= ((n - i)); s++) { //上一列选多少 if(j == 0) { f[i][j][k] = max(f[i + 1][max(0, s)][k], f[i][j][k]); } else if(k - j >= 0) f[i][j][k] = max(f[i][j][k], f[i + 1][s][k - j] + sum[j][i]); ans = max(ans, f[i][j][k]); } } } } cout<<ans<<endl; return 0; }

2|0Circle

在这里插入图片描述
这道题难的就是问题转化

如果一个序列为 101001100 101001100 101001100,我们发现答案就是由 0 0 0隔开的连续 1 1 1的周期的 l c m lcm lcm

那么一段连续 1 1 1的方格的周期是多少,手玩可得 c n t + 3 cnt+3 cnt+3, c n t cnt cnt为连续 1 1 1的个数

那么问题就转化为了 ∑ c n t i < = 150 \sum cnt_i<=150 cnti<=150, l c m ( c n t 1 + 3 , c n t 2 + 3 , c n t 3 + 3... ) lcm(cnt_1+3,cnt_2+3,cnt_3+3...) lcm(cnt1+3,cnt2+3,cnt3+3...)的个数

设计状态 f [ i ] f[i] f[i]表示前 i i i个位置的 l c m lcm lcm个数,且 i i i个位置一定放 1 1 1

发现, l c m ( c n t ) lcm(cnt) lcm(cnt)最大也不会爆 L L LL LL,最大的为选择5个30左右的质数相乘

考虑用 s e t set set转移, f [ i ] f[i] f[i]表示前 i i i个位置且第 i i i个位置一定放 1 1 1 l c m lcm lcm种类

那么考虑第 i i i个位置会向前填充多少 j j j个连续的 1 1 1,为保证状态的合法, f [ i ] f[i] f[i]应由 f [ j − 1 ] f[j-1] f[j1]转移而来,保证 i i i向前的是单独的一段,解释起来太麻烦了,直接看代码

f[0].insert(1);//初始化 f[1].insert(1); for(int i = 2; i <= 150; i++) { for(int j = i - 2; j >= 0; j--) { //保证是单独的一段 for(auto k : f[j]) { LL lcmnow = (1LL * k * (i - j + 2) / __gcd(k, 1LL * (i - j + 2))); f[i].insert(lcmnow); } } } for(int i = 1; i <= 150; i++) { printf("%d ,\n", f[i].size()); //size即为答案 for(auto y : f[i]) { f[i + 1].insert(y);//后面可以不填,对i个位置,f[i-1],f[i-2],f[i-3]..的答案也是合法的,类似前缀搞一下 } }

做完发现时间复杂度偏高,但是150非常小,直接打表即可

//问题转化, 转方格的周期 == lcm(ai + 3)的个数 #include<bits/stdc++.h> using namespace std; #define LL long long const int MAX = 160; unordered_set<LL> f[MAX]; int ans[151] = { 0, 1 , 2 , 3 , 4 , 6 , 8 , 11 , 13 , 18 , 21 , 26 , 31 , 37 , 45 , 51 , 58 , 66 , 78 , 88 , 100 , 114 , 128 , 145 , 163 , 180 , 200 , 222 , 245 , 274 , 305 , 333 , 367 , 402 , 443 , 486 , 529 , 574 , 629 , 686 , 741 , 807 , 872 , 939 , 1016 , 1100 , 1184 , 1277 , 1371 , 1476 , 1593 , 1708 , 1826 , 1962 , 2100 , 2246 , 2408 , 2571 , 2745 , 2939 , 3129 , 3331 , 3556 , 3780 , 4018 , 4279 , 4547 , 4826 , 5129 , 5440 , 5773 , 6127 , 6477 , 6861 , 7279 , 7693 , 8134 , 8610 , 9092 , 9606 , 10160 , 10709 , 11296 , 11926 , 12563 , 13252 , 13979 , 14704 , 15480 , 16306 , 17148 , 18043 , 18975 , 19920 , 20950 , 22031 , 23112 , 24270 , 25492 , 26718 , 28038 , 29424 , 30815 , 32303 , 33862 , 35451 , 37152 , 38906 , 40686 , 42602 , 44597 , 46612 , 48765 , 50991 , 53269 , 55715 , 58222 , 60770 , 63504 , 66323 , 69185 , 72257 , 75410 , 78619 , 82047 , 85591 , 89214 , 93045 , 96967 , 101005 , 105318 , 109711 , 114201 , 118995 , 123890 , 128930 , 134279 , 139725 , 145307 , 151253 , 157314 , 163550 , 170152 , 176876 , 183799 , 191137 , 198616 , 206295 , 214387 , 222649 , 231205}; int main() { freopen("circle.in","r",stdin); freopen("circle.out","w",stdout); int n; while(~scanf("%d", &n)) { printf("%d\n", ans[n]); } // f[0].insert(1); // f[1].insert(1); // for(int i = 2; i <= 150; i++) { // for(int j = i - 2; j >= 0; j--) { // for(auto k : f[j]) { // LL lcmnow = (1LL * k * (i - j + 2) / __gcd(k, 1LL * (i - j + 2))); // f[i].insert(lcmnow); // } // } // printf("i %d \n", i); // } // printf("***\n"); // for(int i = 1; i <= 150; i++) { // printf("%d ,\n", f[i].size()); // for(auto y : f[i]) { // f[i + 1].insert(y); // } // } return 0; }

__EOF__

本文作者userName
本文链接https://www.cnblogs.com/Nogtade/p/17815972.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Nogtade  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示