[CF1294E] Obtain a Permutation

给定一个 (n imes m) 矩阵,其中元素为 (1 o nm) 的一个排列,每次操作可以任选一个元素将它变为任意整数,或者选择一列将其循环移位(向上)一格,求使得矩阵变为标准型的最少操作次数

Solution

(a[i][j])(i)(j) 列的数,(c[i][j]) 表示第 (j) 列循环移位 (i) 次后有多少个数已经匹配,则答案为

[sum_{j=1}^m (min_{i=0}^{n-1} (i+n-c[i][j])) ]

考虑如何计算 (c),由于每个元素只会对一个 (c[?][?]) 产生贡献,所以我们判断每个元素是否可能被填在当列,如果可能,计算应该被填在的位置,算出坐标差值,然后对对应的 (c[?][?]) 计算贡献就好了

#include <bits/stdc++.h>
using namespace std;

#define int long long

int n,m,**a,**c;

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    a=new int* [n+1];
    c=new int* [n+1];
    for(int i=0;i<=n;i++) {
        a[i]=new int[m+1];
        c[i]=new int[m+1];
        for(int j=0;j<=m;j++) c[i][j]=0;
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            cin>>a[i][j];
            if(a[i][j]<j||a[i][j]>n*m||(a[i][j]-j)%m) continue;
            c[((i-(a[i][j]-1)/m-1)%n+n)%n][j]++;
        }
    }
    int ans=0;
    for(int j=1;j<=m;j++) {
        int tmp=1e9;
        for(int i=0;i<n;i++) tmp=min(tmp,i+n-c[i][j]);
        ans+=tmp;
    }
    cout<<ans;
}

原文地址:https://www.cnblogs.com/mollnn/p/12591992.html