牛客练习赛42 出题的诀窍(数学+hash)

出题的诀窍

题目链接:https://ac.nowcoder.com/acm/contest/393/C

题解:

由于他是在每一行选取一个元素,然后纵向来比较,这里行的顺序是不会影响的,所以我们将每一个数存入哈希表中,然后对每一个数来进行考虑。

第一行的数,对答案的贡献为mn-1,而第二行对答案的贡献为mn-2*(m-1)...以此类推。

这里注意对同一行有多个相同元素的情况考虑一下。

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int  N = 2005, M = 3000484, MOD = 1e9 + 7;
ll a[N][N], pm[N];
int n, m;
struct Edge {
    ll v, next, i;
} e[N * N];
ll head[M], tot, h[M];
ll f[N * N], d[N * N];
void adde(ll u, ll v, ll i) {
    e[tot].i = i;
    e[tot].v = v;
    e[tot].next = head[u];
    head[u] = tot++;
}
void hsh(ll x, ll y) {
    ll now = x % M;
    while(h[now] != -1 && h[now] != x) {
        now += 1;
        if(now >= M)
            now -= M;
    }
    h[now] = x;
    adde(now, x, y);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> m >> n;
    memset(head, -1, sizeof(head));
    memset(h, -1, sizeof(h));
    pm[0] = 1;
    for(int i = 1; i <= n; i++)
        pm[i] = pm[i - 1] * m % MOD;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            cin >> a[i][j];
            hsh(a[i][j], i);
        }
    }
    ll ans = 0, cnt, num, pr;
    for(int x = 0; x < M; x++) {
        if(h[x] != -1) {
            pr = 1;
            cnt = 0;
            num = 0;
            for(int i = head[x]; i != -1; i = e[i].next) {
                d[++cnt] = e[i].i;
            }
            for(int i = 1; i <= cnt; i++) {
                if(i == 1 || d[i] != d[i - 1])
                    f[++num] = 1;
                else
                    f[num]++;
            }
            for(int i = 1; i <= num; i++) {
                ans += pm[n - i] * pr % MOD * f[i] % MOD * h[x] % MOD;
                pr = pr * (m - f[i]) % MOD;
                ans %= MOD;
            }
        }
    }
    cout << ans;
    return 0;
}

 

posted @ 2019-03-21 20:56  heyuhhh  阅读(138)  评论(0编辑  收藏  举报