Obtain a Permutation

题目链接

题目描述:

 

 Input:

The first line of the input contains two integers nn and mm (1n,m2105,nm21051≤n,m≤2⋅105,n⋅m≤2⋅105) — the size of the matrix.

The next nn lines contain mm integers each. The number at the line ii and position jj is ai,jai,j (1ai,j21051≤ai,j≤2⋅105).

Output:

Print one integer — the minimum number of moves required to obtain the matrix, where a1,1=1,a1,2=2,,a1,m=m,a2,1=m+1,a2,2=m+2,,an,m=nma1,1=1,a1,2=2,…,a1,m=m,a2,1=m+1,a2,2=m+2,…,an,m=n⋅m (ai,j=(i1)m+jai,j=(i−1)m+j).

 

Examples:

input1:

3 3

3 2 1

1 2 3

4 5 6

output1:

6

input2:

4 3

1 2 3

4 5 6

7 8 9

10 11 12

output2:

0

input3:

3 4

1 6 3 4

5 10 7 8

9 2 11 12

output:

2

思路:

先观察一下两种操作:

  • 单点修改
  • 整列上移

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

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

ans = \sum_{j = 1}^{m}\left( \min\limits_{0 \le i < n } \left(i + n - same_{j, i} \right) \right)ans=j=1m(0i<nmin(i+nsamej,i))

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

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

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

  • 如果 i \ge kik,移动 i - kik 个单位即可;
  • 如果 i < ki<k,那首先把它移到第 11 行需要 i - 1i1 次,然后再移 11 次到第 nn 行,从第 nn 行移到第 kk 行需要 n - knk 次,加起来,就是 i - 1 + 1 + n - ki1+1+nk,化简得 i - k + nik+n。

如果合并的话,就是要移动 (i - k + n) \bmod n(ik+n)modn 次,那么我们就可以把 same_{j, (i - k + n) \bmod n}samej,(ik+n)modn 增加 11 了。

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

#include<bits/stdc++.h>
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef unsigned long long ull;
typedef  long long ll;
typedef pair<ll,ll> pi;
#define IOS std::ios::sync_with_stdio(false)
#define ls p<<1
#define rs p<<1|1
#define mod 1000000000 + 7
#define PI acos(-1.0)
#define INF   1e18
#define eps 1e-8
#define N 2000000 + 5
/*********************Code*********************/
ll n,m,s[N],ans;
vector<ll>a[N];
int main(void){
    IOS;
    cin>>n>>m;
    for(ll i = 1;i <=n;i++){
        a[i].push_back(0);
        for(ll j = 1;j <=m;j++){
            ll x;
            cin>>x;
            a[i].push_back(x);
        }
    }
    for(ll j = 1;j <=m;j++){
        ll tans = INF;
        for(ll i = 0;i < n;i++)
            s[i] = 0;
        for(ll i = 1;i <=n;i++){
            if(a[i][j]<j||a[i][j]>n*m||(a[i][j]-j)%m)
                continue;
            ll k = (a[i][j]-j)/m+1;
            s[(i-k+n)%n]++;
        }
        for(ll i = 0;i < n;i++)
            tans = min(tans,i+n-s[i]);
        ans +=tans;
    }
    cout<<ans<<endl;
    return 0;
}

 

 
posted @ 2021-04-06 20:52  阿涅—Rachel  阅读(41)  评论(0)    收藏  举报