Tミミズ問題の解決策

ミミズ

この質問では、記号\([c] \)を使用してcに切り捨てることを示します。たとえば、\([3.0] = [3.1] = [3.9] = 3 \)のようにします。ミミズは最近災害になりました!隣のノミの国のノミはミミズを捕まえることができなかったので、クリケット王は剣士にミミズを破壊するのを手伝わせなければなりませんでした。クリケット今や王国の合計\(N \)のみミミズは(\(N \)は正の整数です)。各ワームは、我々は長さ設定している\(I \)のみミミズ長さ\(a_iを式(I = 1,2、... \)、N-) およびすべての長さは非負の整数であることを保証するために(すなわち.:長さ\(0 \)のミミズがいる場合があります)。毎秒、剣士はすべてのミミズの中で最も長いものを見つけ(多数ある場合は1つ選択)、それを半分に切断します。ミミズを切る魔法のナイフの手の位置は、定数\(p \)\(0 <p <1 \)を満たす有理数によって決定されます。このミミズの長さが\(x \)の場合、魔法のナイフの手は
長さ\([px] \)\(x- [px] \)の 2つのミミズに切り分けます。特に、これら2つの数値のいずれかが0の場合、長さが0のミミズも保持されます。さらに、作成されたばかりの2つのミミズを除いて、残りのミミズの長さは\(q \)(負でない整数定数)だけ増加します。ミミズはますます成長するだけでなく、より長く成長するため、クリケット王はこれが長期的な解決策ではないことを知っていました。クリケット王は大きな力を持つ神秘的な人物に目を向けることに決めましたが、必要な救助は\(m \)秒が来る可能性があります...(\(m \)は負でない整数です)キングクリケットはこのm秒の状況を知りたいと思っています。具体的には、彼は知りたいと思っています:?\(m \)秒で、1秒ごとに切り取られたミミズの長さ(\(m \)の数)が切り取られるまで\(m \)秒後、すべてのミミズ長さ(\(n + m \)番号があります)。クリケット王は確かに
何をすべきか知っています!しかし、彼はあなたをテストしたい...

入力

最初の行には、6つの整数\(n、m、q、u、v、t \)が含まれています。ここで、\(n、m、q \)意味については、問題の説明を参照してください。
\(u、v、t \)すべて正の整数です。\(p = u / v \)を計算する必要があります(保証\(0 <u <v \)\(t \)は出力パラメーターであり、その意味は出力形式で説明されます。
2行目には、n(負でない整数)、つまり\(a_i、a_2、...、a_n \)が含まれています。これは最初のミミズの長さ\(n \)です。
同じ行の隣接する2つの数字の間は、スペースで区切るだけです。
保証\(1 <= n <= 10 ^ 5、0 <m <7 * 10 ^ 6、0 <u <v <10 ^ 9、0 <= q <= 200、1 <t <71、0 <ai <10 ^ 8 \)

出力

最初の行は、\([m / t] \)整数を時系列で出力します。最初の\(t \)秒、最初の\(2t \)秒、最初の\(3t \)秒...ミミズは切り捨てられます(カットされる前の)長さ。
2行目は\([(n + m)/ t] \)整数を出力し、m秒後のミミズの長さが出力されます。
ランキングは\(t \)出力し、次に\(2tを大きいものから小さいものの順に出力する必要があります。\)、セクションの長さ\(3t \) ......
同じ行の隣接する2つの数字の間は、スペースで区切るだけです。特定の行に出力する番号がない場合でも、空白行を出力する必要があります。
この形式を理解するには、サンプルをお読みください。

入力例

3 7 1 1 3 1
3 3 2

出力例

3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2

解決策

ACの問題を解決できるコードを見つけることが非常に重要であることが事実によって証明されています。
%YouXamの問題の解決策

問題解決のアイデア

隠されたトピックの特性:単調に
にカット長ミミズミミズの一定の割合後ミミズミミズに第一切断され
、これがことが理解されるべき
2つのワームであると仮定すると、\(A、B \)項、\ (a> b \)。次に、\(a_1、a_2 \)にカットされます。\(t \)秒後に、\(b \)\(b_1、b_2 \)にカットされます。このとき、\(a_1、a_2 \)の長さは\(l_ {a_1} + t = p * l_ {a} + t、l_ {a_2} + t =(1-p)* l_a + t \)です。そして\(B_1、B_2 \)の長さが、のために、\(P *(L_B + T)、(1-P)*(I_B + T)\)を参照することが容易である\(L_ {A_1}> L_ {B_1を} 、l_ {a_2}> l_ {b_2} \)
これを使用するため STLで優先キューを使用する必要はありません
毎回カットされる2つのセグメントに2つの通常キューを使用するのは誤りです。このキューは当然単調です。オフ

コード

#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
const long long M = 0x3f3f3f3f3f3f3f3f;
int n, m, q, u, v, t, a[100005], cnt = 1, s = 0, f;
queue<int> q1, q2;
int main() {
    scanf("%d%d%d%d%d%d", &n, &m, &q, &u, &v, &t);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    sort(a+1, a+n+1, greater<int>());//greater<int>()用到库<set>
    for(int i = 1; i <= m; i++) {
        long long d = -M;
        if (cnt <= n && d < a[cnt])
            d = (long long)a[cnt], f = 0;
        if (q1.size() && d < q1.front())
            d = (long long)q1.front(), f = 1;
        if (q2.size() && d < q2.front())
            d = (long long)q2.front(), f = 2;
        if (f == 1) q1.pop();
        else if (f == 2) q2.pop();
        else cnt++;
        d += s;
        q1.push(d * u / v - s - q);
        q2.push(d - d * u / v - s - q);
        s += q;
        if (i % t == 0) printf("%lld ", d);
    }
    puts("");
    for(int i = 1; i <= m + n; i++) {
        long long d = -M;
        if (cnt <= n && d < a[cnt])
            d = (long long)a[cnt], f = 0;
        if (q1.size() && d < q1.front())
            d = (long long)q1.front(), f = 1;
        if (q2.size() && d < q2.front())
            d = (long long)q2.front(), f = 2;
        if (f == 1) q1.pop();
        else if (f == 2) q2.pop();
        else cnt++;
        if (i % t == 0) printf("%lld ", d + s);
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/Z8875/p/12721123.html