zoukankan      html  css  js  c++  java
  • Codeforces 1294E Obtain a Permutation

    Description

    描述

    给一个 $n imes m$ 的矩阵,你想要把它还原成如下的矩阵:

    你有两种操作:

    • 选择一个数,修改它的值。
    • 选择一列,每个元素上移一位,第一行的元素移到第 $n$ 行。

    求还原的最小操作次数。

    输入

    第一行两个正整数 $n, m$($1 le n, m le 2 imes 10^5$,$n imes m le 2 imes 10^5$)。

    接下来是一个 $n imes m$ 的矩阵 $a_{i, j}$($1 le a_{i, j} le 2 imes 10^5$)。

    输出

    一个数表示答案。

    样例

    输入1

    3 3
    3 2 1
    1 2 3
    4 5 6

    输出1

    6

    输入2

    4 3
    1 2 3
    4 5 6
    7 8 9
    10 11 12

    输出2

    0

    输入3

    3 4
    1 6 3 4
    5 10 7 8
    9 2 11 12

    输出3

    2

    解释

    样例1:$a_{1,1}gets 7$,$a_{1,2} gets 8$,$a_{1,3} gets 9$,然后每列上移一次。

    样例2:矩阵已经还原。

    样例3:上移第 $2$ 列 $2$ 次。

    Solution

    先观察一下两种操作:

    • 单点修改
    • 整列上移

    发现了什么?不同列之间互不影响,所以我们可以对于每一列分开处理。

    那么,对于一列 $j$,因为“先修改,后上移”和“先上移,后修改”没有本质区别,所以我们定义 $same_{j, i}$($0le i <n $)表示将第 $j$ 列上移 $i$ 个单位后,有几个数是不用变的。那么上移了 $i$ 个单位以后,自然还有 $n - same_{j, i}$ 个数是需要变的,那么就要花费 $n - same_{j,i}$ 次修改操作,上移也花费了 $i$ 次操作,那第 $j$ 列的最优方案就是 $minlimits_{0 le i < n } left(i + n - same_{j, i} ight)$,最终答案就是:

    $$ans = sum_{j = 1}^{m}left( minlimits_{0 le i < n } left(i + n - same_{j, i} ight) ight)$$

    现在唯一的问题就是如何求出 $same$ 了。我们发现,如果一个数 $a_{i, j}$ 是 应该出现在第 $oldsymbol{j}$ 列 的数字,那么一定有 $j le a_{i,j} le n imes m$,同时 $a_{i, j} equiv j pmod{m}$(后者在代码里写作了  (a[i][j] - j) % m )。

    如果上面的条件满足了,那我们就可以算一下 $a_{i,j}$ 这个数字应该出现在哪一行。显然,它应该出现在 $dfrac{a_{i,j} - j}{m} + 1$ 行(记作 $k$)。

    那如果我们把 $a_{i,j}$ 移到第 $k$ 行,它就不用变了。回顾 $same$ 的定义,从第 $i$ 行移到第 $k$ 行,要移动几次呢?

    • 如果 $i ge k$,移动 $i - k$ 个单位即可;
    • 如果 $i < k$,那首先把它移到第 $1$ 行需要 $i - 1$ 次,然后再移 $1$ 次到第 $n$ 行,从第 $n$ 行移到第 $k$ 行需要 $n - k$ 次,加起来,就是 $i - 1 + 1 + n - k$,化简得 $i - k + n$。

    如果合并的话,就是要移动 $(i - k + n) mod n$ 次,那么我们就可以把 $same_{j, (i - k + n) mod n}$ 增加 $1$ 了。

    注意 $n, m$ 都有可能达到 $2 imes 10^5$,所以需要开不定长数组,时间复杂度 $mathcal O(nm)$。$same$ 可以每列重复使用,舍去前一个维度。

    代码贴出,仅供参考。

    #include <bits/stdc++.h>
    using namespace std;
    const int NM = 2e5 + 5;
    int n, m, same[NM], ans;
    vector<int> a[NM];
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++)
    	{
    		a[i].push_back(0); // 下标凑成从 1 开始
    		for(int j = 1; j <= m; j++)
    		{
    			int val;
    			cin >> val;
    			a[i].push_back(val);
    		}
    	}
    	for(int j = 1; j <= m; j++)
    	{
    		int tans = INT_MAX;
    		for(int i = 0; i < n; i++) same[i] = 0;
    		for(int i = 1; i <= n; i++)
    		{
    			if(a[i][j] < j || a[i][j] > n * m || (a[i][j] - j) % m != 0) continue;
    			int k = (a[i][j] - j) / m + 1;
    			same[(i - k + n) % n]++;
    		}
    		for(int i = 0; i < n; i++) tans = min(tans, i + n - same[i]);
    		ans += tans;
    	}
    	cout << ans << endl;
    	return 0;
    }
  • 相关阅读:
    使用iText 7读取PDF文件中的文本和图片
    登记或取消登记盈亏库存日记账行数量
    uni-app(未完)
    javaScript的基本优雅写法
    ModuleFederation-模块联邦
    typescript
    img标签src图片路径根目录问题
    开源工具分享
    软件缺陷的度量、分析和统计
    MIT6.824 2020 Lab2 A Raft Leader Election
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF1294E.html
Copyright © 2011-2022 走看看