D2. Seating Arrangements (hard version)

该博客讨论了一个关于电影院座位分配的问题,目标是使视力不佳的观众获得更好的座位,同时在人们入座时最小化他们经历的不便。通过模拟入座过程并使用树状数组动态更新占用状态,可以找到总不便的最小值。代码实现中包含了问题的输入输出示例及解决方案的详细步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:
It is the hard version of the problem. The only difference is that in this version 1≤n≤300

In the cinema seats can be represented as the table with n rows and m columns. The rows are numbered with integers from 1 to n. The seats in each row are numbered with consecutive integers from left to right: in the k-th row from m(k−1)+1 to mk for all rows 1≤k≤n.

在这里插入图片描述There are nm people who want to go to the cinema to watch a new film. They are numbered with integers from 1 to nm

. You should give exactly one seat to each person.

It is known, that in this cinema as lower seat index you have as better you can see everything happening on the screen. i
-th person has the level of sight ai. Let’s define si as the seat index, that will be given to i-th person. You want to give better places for people with lower sight levels, so for any two people i, j such that ai<aj it should be satisfied that si<sj

.After you will give seats to all people they will start coming to their seats. In the order from 1 to nm, each person will enter the hall and sit in their seat. To get to their place, the person will go to their seat’s row and start moving from the first seat in this row to theirs from left to right. While moving some places will be free, some will be occupied with people already seated. The inconvenience of the person is equal to the number of occupied seats he or she will go through.

Let’s consider an example: m=5 , the person has the seat 4 in the first row, the seats 1, 3, 5 in the first row are already occupied, the seats 2 and 4 are free. The inconvenience of this person will be 2, because he will go through occupied seats 1 and 3

.Find the minimal total inconvenience (the sum of inconveniences of all people), that is possible to have by giving places for all people (all conditions should be satisfied).

Input:
7
1 2
1 2
3 2
1 1 2 2 3 3
3 3
3 4 4 1 1 1 1 1 2
2 2
1 1 2 1
4 2
50 50 50 50 3 50 50 50
4 2
6 6 6 6 2 2 9 6
2 9
1 3 3 3 3 3 1 1 3 1 3 1 1 3 3 1 1 3

Output:
1
0
4
0
0
0
1

分析:
按照题意先记录下每个人的座位号,ai相同的人的座位号进行特殊处理,然后按顺序模拟入座过程,用树状数组维护

Code:

#include <bits/stdc++.h>
#define DEBUG freopen("_in.txt", "r", stdin);
// #define DEBUG freopen("_in.txt", "r", stdin), freopen("_out.txt", "w", stdout);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll maxn = 1e5 + 10;
const ll maxm = 1e3 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double pi = 3.1415926;
const ll mod = 998244353;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

ll t, n, m;

struct Node
{
    ll v, pos, fl;
    bool operator<(Node other) const
    {
        if (v != other.v)
            return v < other.v;
        else
        {
            return pos < other.pos;
        }
    }
} nodes[maxn];

ll arr[maxn], c[maxm][maxm], brr[maxn];
map<ll, ll> mp;

ll lowbit(ll i)
{
    return i & (-i);
}

void update(ll x, ll v, ll fl)
{
    for (ll i = x; i <= m; i += lowbit(i))
    {
        c[fl][i] += v;
    }
}

ll query(ll x, ll fl)
{
    ll sum = 0;
    for (ll i = x; i > 0; i -= lowbit(i))
    {
        sum += c[fl][i];
    }
    return sum;
}

int main()
{
    // DEBUG;
    scanf("%lld", &t);
    while (t--)
    {
        mp.clear();
        scanf("%lld%lld", &n, &m);
        for (ll i = 1; i <= m * n; i++)
        {
            scanf("%lld", &nodes[i].v);
            nodes[i].pos = i;
        }
        sort(nodes + 1, nodes + m * n + 1);
        ll index = 0;
        for (ll i = 1; i <= m * n; i++)
        {
            if (i > 1 && nodes[i].v == nodes[i - 1].v)
            {
                arr[nodes[i].pos] = index;
            }
            else
                arr[nodes[i].pos] = ++index;
            mp[index]++;
        }
        ll sum = 0;
        for (ll i = 1; i <= index; i++)
        {
            if (mp[i] > 1)
            {
                ll num1 = i + sum, fl1 = ceil(num1 * 1.0 / m);
                ll num2 = i + sum + mp[i] - 1, fl2 = ceil(num2 * 1.0 / m);
                if (fl1 == fl2)
                {
                    for (ll j = 0; j < mp[i]; j++)
                    {
                        // nodes[num1 + j].pos
                        brr[nodes[num1 + j].pos] = num2 - j;
                    }
                }
                else
                {
                    ll sub = fl2 - fl1;
                    ll pos1 = i + sum - 1;
                    for (ll j = 0; j <= fl1 * m - num1; j++)
                    {
                        brr[nodes[++pos1].pos] = fl1 * m - j;
                    }

                    for (ll j = 1; j <= sub - 1; j++)
                    {
                        for (ll k = 0; k <= m - 1; k++)
                        {
                            brr[nodes[++pos1].pos] = (fl1 + j) * m - k;
                        }
                    }
                    for (ll j = 0; j <= num2 - (fl2 - 1) * m - 1; j++)
                    {
                        brr[nodes[++pos1].pos] = num2 - j;
                    }
                }
                sum += mp[i] - 1;
            }
            else
                brr[nodes[i + sum].pos] = i + sum;
        }
        ll ans = 0;
        for (ll i = 1; i <= m * n; i++)
        {
            ll v = brr[i] % m, u = ceil(brr[i] * 1.0 / m);
            if (v == 0)
            {
                v = m;
            }
            ans += query(v, u);
            update(v, 1, u);
        }
        printf("%lld\n", ans);
        for (ll i = 1; i <= n; i++)
        {
            for (ll j = 1; j <= m; j++)
            {
                c[i][j] = 0;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值