[CodeJam 2021 Round 3] Square Free(调整法 / 字典序最小解网络流)

CodeJam 2021 Round3 Square Free

  • problem
  • solution
  • code
  • code-std

problem

神奈子是个很爱打麻将的老婆婆,有一天她把她的麻将放进了一个 n×mn\times mn×m 的网格图里,每个麻将可以左斜着放入网格中(如 / ),也可以右斜着(如 \ ),如下图所示。不过她还没决定好应该怎么摆。

在这里插入图片描述

因为她很喜欢风,所以摆麻将的地方风很大,容易把麻将吹倒,因此存在两个序列 aaabbb,表示第 iii 行必须有恰好 aia_iai 个麻将左斜,第 jjj 列必须有恰好 bjb_jbj 个麻将左斜,才能保证麻将的稳定性。

因为她很喜欢山,所以她喜欢山一般的参差不齐感,而不希望麻将形成规规整整的正方形(如下图所
示)。

在这里插入图片描述

她非常没耐心,所以你需要告诉她能否将麻将摆成符合要求的样子,如果可以,为了节省她的时间,你只需要任意给出一种方案即可 。

n,m≤20n,m\le 20n,m20

solution

20简直就是各种算法和高复杂度爆艹

在考场上的 调整法 竟然过了,我也不知道对不对。 还是分享给大家。

这种给出任意一种方案,一般都是猜结论或者单纯构造。

这里我从构造入手。

先考虑行的限制,每行从第一列开始直接就放 aia_iai/,剩下的放 \。每一行形如 //...//\\..\

这样首先是将行限制全都满足了,在此基础上继续考虑列的限制。

从左往右每一列每一列的考虑,考虑到第 iii 列的时候,要求前 i−1i-1i1 列全都已经符合要求。

  • 该列的 / 恰好满足要求那就直接下一列。

  • 该列的 / 大于要求。那么就需要将该列上的某几行 / 替换成 \

    直接枚举每一行 kkk ,然后再枚举 kkk 行后面 j(j>i)j(j>i)j(j>i) 列的情况。

    如果 kkkiii 列恰好是 /,且 kkk 行某个 jjj 列恰好是 \,那么就可以交换两个位置上的字符。

    kkk 行的限制仍然满足,也没有改动前 i−1i-1i1 列。

    后面列的改变后面调整再说,现在只对前面负责。

  • 该列的 / 小于要求。与上面同理,需要将该列上的某几行 \ 替换成 /。不赘述。

以上是第一步调整。有可能还不行,就需要进行第二步调整。

以该列的 / 大于要求为例,可能会出现该列上的每个 \ 所在行的 ∀j,j>i\forall j,j>ij,j>i 列都是 \

那么就找不到可以与该位置交换的 / 了。

这个时候就只能动前面的了。

考虑 iii 列的某行 j1j_1j1,该 (j1,i)(j_1,i)(j1,i) 格子字符为 /,考虑现在将其调整为 \

那么首先找到 j1j_1j1 行的 x(x<i)x(x<i)x(x<i) 列,(j1,x)(j_1,x)(j1,x) 格子字符为 /

如果这两个交换,则第 iii 列的 / 数量就会减少 111,且 j1j_1j1 行的限制没有破坏。

此时发现,xxx 列的限制破环了,再找一行 j2j_2j2(j2,x)(j_2,x)(j2,x) 上的字符为 \,将其改变成 /,又重新维护了 xxx 列的限制。

又发现 j2j_2j2 行的限制被破坏,又得找一个 yyy 列,继续调整..................

会发现 j2j_2j2 行后面 y(y>i)y(y>i)y(y>i) 列一定有 \

因为既然能进入到第二步的调整,那就证明任意行已经找不到 /

将其改变为 /,那么 j2j_2j2 行的限制就又重新维护了。

不管 iii 列以后的事情,那么所有行和前面所有列的限制仍然成立。

以该列的 / 小于要求同理,也不赘述。

两步调整后,会发现,如果只有第一步调整是永远不会出现正方形的,可是有第二步后就不能保证了。

所以进行第三步对正方形的调整。

而且上述调整发现只可能(?)出现边长为 111 的正方形。

因为上述调整是行列从小到大的。

一定是先将上一行想尽办法的调整了再调整下一行,所以不可能下一行又折回去这种感觉。

直接枚举每个位置为左上角格子,然后判断一个 2×22\times 22×2 格子是否构成正方形,如果是那么交换两行,注意此时不能直接往下枚举。

i.e.

/\
/\
\/

有可能换了后跟上面的重新组成了一个正方形,那就行减减,再判断一遍。

最后三步调整后再判断一下是否又正方形的出现,这是还出现就直接判为 IMPOSSIBLE

很有可能是因为数据太水,导致我错误地艹过去了。哈哈哈哈


以下就是正解算法。

发现只要存在一个满足行列限制的方案,就一定存在没有正方形的方案。

如果存在正方形,可以将正方形所有格子内的字符全反转,仍然满足行列限制,但破环了正方形。

可以证明这样是不会存在环,无限循环下去的。

证明:

将表格字符压成一维的字符串表示,假设 / 的字典序大于 \

那么每次反转一个正方形后,字典序只会变小。

因此字典序最小的方案一定是不存在正方形的。

问题转化为构造一个字典序最小的方案数。

再加上这个行列限制,明显就是网络流经典问题。

具体可见 code-std 实现。

code

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 25
int n, m;
int r[maxn], c[maxn];
//int ROW[maxn], COL[maxn];
int ans[maxn][maxn];int main() {freopen( "net.in", "r", stdin );freopen( "net.out", "w", stdout );scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%d", &r[i] );for( int i = 1;i <= m;i ++ ) scanf( "%d", &c[i] );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= r[i];j ++ )ans[i][j] = 1;for( int j = 1;j <= m;j ++ ) {int cnt = 0;for( int i = 1;i <= n;i ++ )cnt += ans[i][j];if( cnt == c[j] ) continue;if( cnt > c[j] ) {for( int i = 1;i <= n and cnt != c[j];i ++ )if( ans[i][j] ) {for( int k = m;k > j;k -- )if( ! ans[i][k] ) {swap( ans[i][j], ans[i][k] );cnt --;break;}}for( int i = 1;i <= n and cnt != c[j];i ++ )if( ans[i][j] ) {for( int k = 1;k <= n;k ++ ) {for( int w = j - 1;w and i != k;w -- )if( ans[k][w] and ! ans[i][w] )for( int x = m;x > j;x -- )if( ! ans[k][x] ) {cnt --;ans[i][j] = 0;ans[i][w] = 1;ans[k][w] = 0;ans[k][x] = 1;goto nxtj;}}nxtj:;}}else {for( int i = 1;i <= n and cnt != c[j];i ++ )if( ! ans[i][j] ) {for( int k = m;k > j;k -- )if( ans[i][k] ) {swap( ans[i][j], ans[i][k] );cnt ++;break;}}for( int i = 1;i <= n and cnt != c[j];i ++ )if( ! ans[i][j] ) {for( int k = 1;k <= n;k ++ ) {for( int w = j - 1;w and i != k;w -- )if( ans[i][w] and ! ans [k][w] )for( int x = m;x > j;x -- )if( ans[k][x] ) {cnt ++;ans[i][j] = 1;ans[i][w] = 0;ans[k][w] = 1;ans[k][x] = 0;goto nxti;}}nxti :;}}// printf( "START: %d\n", j );// for( int i = 1;i <= n;i ++ ) {//     for( int j = 1;j <= m;j ++ )//         if( ans[i][j] ) printf( "%c", 47 );//         else printf( "%c", 92 );//     puts("");// }if( cnt != c[j] ) return ! printf( "IMPOSSIBLE\n" );}for( int i = 1;i < n;i ++ )for( int j = 1;j < m;j ++ )if( ans[i][j] and ! ans[i][j + 1] and ! ans[i + 1][j] and ans[i + 1][j + 1] ) {swap( ans[i][j], ans[i + 1][j] );swap( ans[i][j + 1], ans[i + 1][j + 1] );i -= 2;break;}for( int i = 1;i < n;i ++ )for( int j = 1;j < m;j ++ )if( ans[i][j] and ! ans[i][j + 1] and ! ans[i + 1][j] and ans[i + 1][j + 1] )return ! printf( "IMPOSSIBLE\n" );printf( "POSSIBLE\n" );for( int i = 1;i <= n;i ++ ) {for( int j = 1;j <= m;j ++ )if( ans[i][j] ) printf( "%c", 47 );// ROW[i] ++, COL[j] ++;else printf( "%c", 92 );puts("");}// for( int i = 1;i <= n;i ++ ) if( ROW[i] != r[i] ) return ! printf( "WA\n" );// for( int i = 1;i <= m;i ++ ) if( COL[i] != c[i] ) return ! printf( "WA\n" );return 0;
}

code-std

#include <bits/stdc++.h>
using namespace std;
#define maxn 25
int a[maxn], b[maxn], r[maxn], c[maxn];
int n, m;bool check( int x, int y ) {memcpy( r, a, sizeof( a ) );memcpy( c, b, sizeof( b ) );for( int i = x;i <= n;i ++ ) {vector < pair < int, int > > v;for( int j = ( i == x ? y : 1 );j <= m;j ++ )v.push_back( { b[j], j } );sort( v.begin(), v.end() );for( int k = v.size() - 1;~ k and a[i];k -- )a[i] --, b[v[k].second] --;}bool flag = 1;for( int i = 1;i <= n;i ++ ) flag &= a[i] == 0;for( int i = 1;i <= m;i ++ ) flag &= b[i] == 0;memcpy( a, r, sizeof( r ) );memcpy( b, c, sizeof( c ) );return flag;
}int main() {scanf( "%d %d", &n, &m );int sum = 0;for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] ), sum += a[i];for( int i = 1;i <= m;i ++ ) scanf( "%d", &b[i] ), sum -= b[i];if( sum ) return ! puts( "IMPOSSIBLE" );if( ! check( 1, 1 ) ) return ! puts( "IMPOSSIBLE" );puts( "POSSIBLE" );for( int i = 1;i <= n;i ++ ) {for( int j = 1;j <= m;j ++ )if( check( i, j + 1 ) ) printf( "\\" );else a[i] --, b[j] --, printf( "/" );puts("");}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P6773 [NOI2020] 命运(dp、线段树合并)

前言 一道看起来很毒瘤但其实还算小清新的题&#xff1f; 理解后感觉其实并没有那么难。 暴力分非常足&#xff0c;好评。 奇妙的线段树合并技巧增加了。 解析 解法1 你是怎么手玩的样例一&#xff1f; 大部分&#xff08;比如我&#xff09;都是容斥吧。 把手玩的方法搬到…

ConsurrentDictionary并发字典知多少?

在上一篇文章你真的了解字典吗?一文中我介绍了Hash Function和字典的工作的基本原理.有网友在文章底部评论,说我的Remove和Add方法没有考虑线程安全问题.https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?redirectedfromMSDN&viewn…

[luogu 4292][bzoj 1758][WC2010] 重建计划(点分治 + dp + 单调队列优化 + 启发式合并)

[WC2010]重建计划problemsolutioncodeproblem 洛谷指路 solution 一看那个道路平均价值的式子&#xff1a;AvgValue∑e∈Sv(e)∣S∣\text{AvgValue}\frac{\sum_{e\in S}v(e)}{|S|}AvgValue∣S∣∑e∈S​v(e)​ 就是 0/1分数规划 的样子。 所以考虑二分最终的答案 midmidmid…

cf1553C. Penalty

cf1553C. Penalty 题意&#xff1a; 有十轮点球&#xff0c;两个队伍轮流进行&#xff0c;1表示进&#xff0c;0表示不进&#xff0c;&#xff1f;表示未知&#xff0c;如果比赛没有了悬念将直接结束。现在让你预测一个情况&#xff0c;使得进行的轮数最少。裁判在决定停止点…

ASP.NET Core 基于JWT的认证(二)

上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍&#xff0c;这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用。.Net Core 2.2Visual Studio 2017ASP.NET Core WebAPI2在上一篇文章中&#xff0c;我们详细的介绍了JWT的知识&#xff0c;这…

P6774 [NOI2020] 时代的眼泪(分块)

前言 看到题目名&#xff1a;别骂了别骂了。 一道很中规中矩的YNOI吧。 卡在整块对整块的贡献上了。 这也确实算是本题最不好做的部分了。 前置知识&#xff1a;Yuno loves sqrt technology I 解析 区间逆序对加强版&#xff1f;很难不想到两道 YLST。 然而多了两维限制&a…

[NOIP2021] 数列(计数dp)

solution f[i][j][k][num][p]:2pf[i][j][k][num][p]:2^pf[i][j][k][num][p]:2p 选择了 iii 个&#xff0c;前 p−1p-1p−1 位 (202p−1)(2^0~2^{p-1})(20 2p−1) 已经选了jjj个&#xff0c;低位向高位进位上来 kkk&#xff0c;前 ppp 位已经确定有 numnumnum 个位置为 111&…

Xor sum HDU - 6955

Xor sum HDU - 6955 题意&#xff1a; 给定一个长度为n的整数序列&#xff0c;求其XOR和不小于k的最短连续子序列。 如果有多个相同长度的连续子序列&#xff0c;则打印具有最小左端点的连续子序列。 如果没有连续的子序列开关XOR总和不小于k&#xff0c;只需打印“-1”。 …

模板:子序列自动机(字符串)

所谓子序列自动机&#xff0c;就是根据子序列建立的自动机。 &#xff08;逃&#xff09; 前言 小清新算法。 解析 和其他自动机类似的&#xff0c;我们希望子序列自动机能且只能接受原串的所有子序列。 考虑一个问题&#xff1a;给你一个串 T&#xff0c;如何判断它是否是…

Docker最全教程之Go实战,墙裂推荐(十九)

前言与其他语言相比&#xff0c;Go非常值得推荐和学习&#xff0c;真香&#xff01;为什么&#xff1f;主要是可以直接编译成机器代码&#xff08;性能优越&#xff0c;体积非常小&#xff0c;可达10来M&#xff0c;见实践教程图片&#xff09;而且设计良好&#xff0c;上手门槛…

[BZOJ3093][Fdu校赛2012] A Famous Game(不等概率)

problem BOZJ3093 solution 逆概率公式&#xff0c;即贝叶斯(Bayes)公式&#xff1a; 假设 B1,B2,...,BnB_1,B_2,...,B_nB1​,B2​,...,Bn​ 是 Ω\OmegaΩ 的一个分割&#xff0c;P(A)>0P(A)>0P(A)>0&#xff0c;则有 P(Bk∣A)P(ABk)P(A)P(Bk)P(A∣Bk)∑i1nP(Bi)…

Mod, Or and Everything HDU - 6950

Mod, Or and Everything HDU - 6950 题意&#xff1a; 给你一个n,问(n%1) or (n%2) or … or (n %n)的值 题解&#xff1a; 无论n为奇偶&#xff0c;定义m(n-1)/2&#xff0c; 我们发现n mod i<m&#xff0c;而当i<m时&#xff0c;有n mod (n-i) i ,于是就有n mod i …

你注意到 .Net Framework 和 .Net Core 中使用 Session 的区别了吗?

在测试一个例子时发现的问题&#xff0c;这个示例实现的功能是刷新页面也能保持表格锁定列的状态&#xff0c;先看下页面的完成效果&#xff1a;测试中发现&#xff0c;几乎相同的代码&#xff1a;在 FineUIMvc&#xff08;Net Framework&#xff09;下没有问题&#xff1a;htt…

模板:拉格朗日乘子法(数学)

所谓拉格朗日乘子法&#xff0c;就是拉格朗日发明的乘子法。 &#xff08;逃&#xff09; 前言 曾经&#xff0c;我被它爆杀&#xff1b;如今&#xff0c;不同的日子&#xff0c;同样的题目&#xff0c;我却不再是曾经的我了。 因为我写模拟退火了。 也不能老是这么混着&…

[UOJ299][CTSC2017] 游戏

【CTSC2017】游戏 problem UOJ299 solution 定义 Xi:X_i:Xi​: 当前已知条件第 iii 局的状态 1/01/01/0&#xff08;胜/败&#xff09;。 将 XiCiX_iC_iXi​Ci​ 记为事件 AiA_iAi​。 假设现在已知条件共有 sss 个&#xff0c;即&#xff1a;第 k1∼sk_{1\sim s}k1∼s​…

Alice and Bob

Alice and Bob 题意&#xff1a; 两人博弈&#xff0c;每次一个人从一堆中拿k个&#xff0c;同时从另一堆拿k * s(s>0)个&#xff0c;问谁先不能拿 10000组数据,N<5000 题解&#xff1a; (x,y)表示第一堆石头数量为x&#xff0c;第二堆为y 如果(x,y)是必败状态&#…

一键发布部署vs插件[AntDeploy]开源了

deploy to remote server by one button click功能支持docker一键部署(支持netcore)支持iis一键部署(支持netcore和framework)(支持增量发布)(支持一键回滚)(支持点火)支持windows服务一键部署(支持netcore和framework)(支持增量发布)(支持一键回滚) 使用插件前我要发布一个net…

CF1257F Make Them Similar(meet in the middle,模拟退火)

前言 sto 退火大师_slb orz sto 正解大师_KHIN orz 只有我啥也不会&#xff0c;哈哈。 有趣的是&#xff0c;两种方法我都想到了一部分&#xff0c;然后都寄掉了。 这有趣个锤子。 解析 Sol1 考虑枚举最终的popcount&#xff0c;然后限制就变成了一个类似于高斯消元的形式…

Find 3-friendly Integers

Find 3-friendly Integers 题意&#xff1a; 定义一个自然数是精妙的&#xff0c;如果他存在一个字串(允许前导0)是3的倍数 问L到R中精妙的数的个数 题解&#xff1a; 数位dp可以做(但我不会。。。) 用结论来做&#xff0c;当n>100时(即为3位数时)必然是精妙的数&#x…

【学习笔记】平等博弈及常见的公平博弈类型

文章目录平等博弈nim堆SG定理nim和常见的公平博弈模型bash博弈nim博弈nim-k博弈wythoff博弈扩展wythoff博弈fibonacci博弈阶梯博弈green hackenbushMisre Nim博弈Every-SGnim积翻棋子游戏游戏的积&#xff0c;tartan定理平等博弈 G{L∣R},LRG\{L|R\},LRG{L∣R},LR&#xff0c;所…