問題設定再戦2010 NOIPユニバーサルソリューション

タイトルと関与アルゴリズム:

  • 統計の数字:質問をはじめ、
  • 水辺へのアクセス:基本的なシミュレーションの質問。
  • ミサイル迎撃:動的計画法、貪欲。
  • 3つのゲーム:貪欲、ゲーム理論。

統計の数字

トピックリンク:羅区P1179
この質問は基本的な質問です。
我々は、可変の開きのみ必要\(CNTを\)統計のために(2 \)\出現回数、および\(Lの\)する(R&LTの\)を\すべての数を横断する(Iは\)\のために、(\ i)は、\、私たちは一人一人がされていない、それを通過する)(2 \を\、そうであれば、その後、\(CNT ++ \) 最終的な出力\(CNTの\は)することができます。
次のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
int cnt, L, R;
void solve(int a) {
    while (a) {
        if (a % 10 == 2) cnt ++;
        a /= 10;
    }
}
int main() {
    cin >> L >> R;
    for (int i = L; i <= R; i ++) solve(i);
    cout << cnt << endl;
    return 0;
}

地下水問題

トピックリンク:羅区P1190
この質問は、私たちは水を開くプロセスをシミュレートし、標準的なシミュレーションタイトル、です。
私たちは、作る([i]は\ w)は\を表し、\を(私は\)それが取る水の個々の開放時間を、そう\(T [i]が\)現在のセクションことを示している\は(私は\)人々が良好な水を取る水に接続されたタップ瞬間。
したがって、最初の我々はよりトラバース\(0 \)する(M-1 \)を\座標\(Iは\) そう\(T [I] = W [I] \) \(m個\)個体を優先順位の職業は)タップ、
その後、我々はから持っている\(m個\)(N-1 \)\座標横断する\(私は\) 最初のために\(私は\)全てである必要があり、個々の、彼はポジションを挿入する必要があり\(W [J](0 \ルj個の \ LTがM)\) の最小\(J \) 我々は仮定する最小W \([J] \)対応するビット座標\(IDを\)最初、\(iは\)個体が最初に挿入される\(ID \)位置。私たちが作る\(T [ID] + = Wを[I] \) に(これが最初ということを意味\は(私は\)最初に個人\(ID \)場所は水を開くために続けます)。
最終的な答えは、すべてのその\(T [i]が(0 \ルI \ LT M)\) (最大のもののうち、最大\(tは[i]が\)レイ築くために最後の人に対応時間)。
次のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int n, m, cnt, w[maxn], t[maxn];
int main() {
    cin >> n >> m;
    if (m > n) m = n;
    for (int i = 0; i < n; i ++) cin >> w[i];
    for (int i = 0; i < m; i ++) t[i] = w[i];
    for (int i = m; i < n; i ++) {
        int id = 0; // id用于表示当前这一轮最早结束的那个队列对应的id
        for (int j = 0; j < m; j ++) if (t[j] < t[id]) id = j;
        t[id] += w[i];
    }
    int ans = 0;
    for (int i = 0; i < m; i ++) ans = max(ans, t[i]);
    cout << ans << endl;
    return 0;
}

しかしながら、上記のコードは最適ではない、その時間複雑である\(O(N \ CDOT M)\)

学びのためにヒープ(ヒープ)の学生このデータ構造、我々はそれでこの問題を解決するために、ヒープを使用することができます。私たちは、せいぜいのサイズを維持することができます\(m個\)要素の最上部から取り出し、それぞれ、小さな根ヒープを\(のt \)誰かが次の場合は、その後、水を築くために最速の個人的な時間という彼は言った、とその後、(その人の数を想定して(私は\)\、我々当時)\(のt + [I]ワット \) スタックにそれらのすべてまでスタックに。
その後、我々は最後の要素は、水の戦いの時間を築くために、最後の一人に対応しますヒープから取り出し、今度はヒープから要素を削除します。
ので、スタックは手動で面倒を達成するために、私たちは私たちに提供するSTLコンテナ使用しているプライオリティキューPRIORITY_QUEUEは小さなヒープルートを実現しています。
次のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
int n, m, w, t, maxt;
priority_queue<int, vector<int>, greater<int> > pq;
int main() {
    cin >> n >> m;
    if (m > n) m = n;
    for (int i = 0; i < m; i ++) {
        cin >> w;   // w表示第i个人打开水所耗费的时间
        pq.push(w);
    }
    for (int i = m; i < n; i ++) {
        cin >> w;
        t = pq.top();
        pq.pop();           // 上一个人打好开水
        pq.push(t + w);     // 下一个人继续打开水
    }
    while (!pq.empty()) {
        maxt = pq.top();
        pq.pop();
    }
    cout << maxt << endl;
    return 0;
}

ミサイル迎撃

トピックリンク:羅区P1158
動的計画法、貪欲:この質問は、アルゴリズムを必要とします。しかし、主に1が、法を見つけるの対象を(教師が法律を見つけることができませんでした、私は説明ゴシップガールを見た後、法を見つけることでした)。
問題の解決策は、「アニー007「Luoguボー・オフを参照してください。https://www.luogu.org/blog/Annie-007/solution-p1158
私たちが最初にクリアする必要があり、この質問のすべてのミサイル迎撃の代わりに、第1のシステムであることが第2のシステムを傍受されます
私たちは、ソート順を考えるデータの範囲のこの質問は、10 ^ 5、おそらくnlogn複雑であることがわかり
、私たちは確かに自身が最初の近くに停止距離第1のシステムにおける最適解、最適解を考えてみましょう
第1は、その遠ミサイルからバーする場合は、実際には、ほぼミサイルのついでに足が傍受、あれば
第1切片aは、我々が昇順に距離1号に従い、すべてのミサイルを置けば確かに私たちのノウハウによりちょうど考えて、あります接頭辞、接尾第2の残りの部分に
、我々は(最後のポイントプレフィックスとして私たちがここで定義されたカットオフポイント)にどのようなこの接頭辞と接尾辞境界点を列挙し
、治療の第1システムコストがプレフィックスカウントが優れています1つのシステムから境界ポイント数
2システムもはや接尾最大であり、その後、我々は必要な前処理アレイのコストを計算するためのソートを見ていない、とDを聞かせすることができ、この時間は、[i]は= iと、それは背後にある最初のと、鉛 爆弾の最大距離
以下のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
long long X1, Y1, X2, Y2, x, y, d[maxn];
int n;
struct Node {
    long long s1, s2;   // s1表示到(x1,y1)的距离;s2表示到(x2,y2)的距离
} a[maxn];
bool cmp(Node a, Node b) {
    return a.s1 < b.s1;
}
int main() {
    cin >> X1 >> Y1 >> X2 >> Y2 >> n;
    for (int i = 0; i < n; i ++) {
        cin >> x >> y;
        a[i].s1 = (x - X1) * (x - X1) + (y - Y1) * (y - Y1);
        a[i].s2 = (x - X2) * (x - X2) + (y - Y2) * (y - Y2);
    }
    sort(a, a+n, cmp);
    for (int i = n-1; i >= 0; i --) {
        d[i] = max(a[i].s2 , d[i+1]);
    }
    long long ans = LONG_LONG_MAX;
    for (int i = 0; i < n; i ++)
        ans = min(ans, a[i].s1 + d[i+1]);
    cout << ans << endl;
    return 0;
}

3つのゲーム

トピックリンク:羅区P1199
貪欲、ゲーム理論:この質問は、アルゴリズムを必要とします。
wjyyyから問題のブログ・ソリューション:https://www.luogu.org/blog/wjyyy/solution-p1199
長いタイトルにもかかわらず、この問題は、主に貪欲なの正しさを証明します。

まず、我々はこの問題では、コンピュータであることがわかり貪欲、それは候補者は、最大の価値を理解する人を選出することが可能になるかに関係なく、言わないことです。2人が同じ目標であるので、ここで考えたのは、ゲーム理論を考えるかもしれません。しかし、ほとんどの分析は、人々は常に最善を得ることがわかります。

私たちはペアリングのプロセスとして見られるだろう選択しているので、選挙の意志IIの後、II最初の行およびii-列のテーブルの行と列が独自の行と列に、私たちがしているので、その将軍の交差点にありますA。そのフォームは対称的です。

サンプルの分析は、常に最適解を学習することができる第二位(フィニッシング)、各行のランキングのための最大のものを。つまり、各行はほとんどありませんコンピュータの最大のグループは、あなたが手を選択できるようにします。あなたは、各行の最大のグループが選出されたことは不可能であるので、コンピュータは常に、奪った前半を扱うことのできる最大のグループを選択したら。そして、我々は大規模および中規模の最大の時間が選択できるようになることであることを証明したいと思います。

私たちは、選出されたに間違いなく第二位の中規模および大規模なラインの最大のライン、コンピュータ意志を選んだとき。

この時点で、我々は、他の時間に最大と中規模の半分を持って、それを伴います。今、私たちは、将軍の最大の可能なペアを得るために人々を得たことを、どのようにコンピュータが自分の将軍が何よりも大きな取得しないことを確実にするには?図から分かるように、そこに選挙は、コンピュータの位置、上側の手に行っている場合(コンピュータが十分にスマートであると仮定して)他の行の最大の位置で、より特定の将軍、現在の値よりも暗黙の了解で、ライン上でそれを取り出します。そして、コンピュータはとてもスマートではありません、それはあなたが将軍の最大値を選出することを選択できないようになる、この時間は、議論に分けることができます。

選択したコンピュータの将軍は、2つの効果があります。人々が停止することができたときに交差点やグリーンラインは、直接、将軍のグループを決定する場合、最初に、オリジナルのグリーンラインと交差します。しかし、我々は今、ラインの交点と緑のラインの値は、いくつかの人々の答えよりも小さくなっている保証することができます。反証:人よりも、その値(五芒星)への答えは、大きな三角形よりも小さくなるようにした場合、その後、第二位の中規模および大規模のこの値は、この値はこの範囲内で可能ではない、であり、その人の価値は三角形よりも大きい場合、三角形最大の中規模および大規模であること。そのため、グリーンラインとの交点は、以上の五芒星ではありません。

第2の効果は、交差し、グリーンラインないということです。いくつかの互いに素とグリーンラインのために、限り、人々は最大のコンピュータをつかむために出て行くように、コンピュータは最大のもので、それぞれの行をつかむことはできません。

要約すると、ヒトまたはコンピュータは、各行をつかむことができないかどうかを最大のこと、貪欲よると、人々は、選択することができます。この時点で大きな選挙に行くために、コンピュータを防ぐことができ、最大の各行の二番目に大きい要素に行くことを選択します要素。同時に、人々が失われることはありません。
次のようにブログのコードは次のとおりです。

#include<cstdio>
#include<algorithm>
using std::sort;
int a[510][510];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
            a[j][i]=a[i][j];
        }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        sort(a[i]+1,a[i]+1+n);
        ans=ans>a[i][n-1]?ans:a[i][n-1];//选出排名第二中最大的那个
    }
    printf("1\n%d\n",ans);//一定有解
    return 0;
}

それから私は私が私のスコアを判断し、ロボットをスコア、そして私が直接出力「1」を獲得していない場合は最終の90得点する前に、コードを見たとき、私はACのすることができた実現。
しかし、第二の試験群では私のプログラムは、私のスコアで測定しているように見えるデータはので、ここで、ロボット未満を獲得するとき、それは私がACコードを得ることができることになりましたが、私の現在の考え方ではなく、最後から二番目の3,4より、第五及び第六行の逆数でありますライン。私はできるだけ早くこの問題に対処しようと、慎重に検討する時間があるそして、疑問に思いました。
(ACが、質問の最終的な出力結果は依然として多いが)、以下のようにコードがあります:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 550;
int g[maxn][maxn], n, belong[maxn];
vector<int> vec, ans1, ans2;

int get_company(int id) {
    int tmp1 = 0, tmp2 = 0;
    for (int i = 1; i <= n; i ++) {
        if (id == i || belong[i]) continue;
        if (g[id][i] > tmp1) { tmp2 = tmp1; tmp1 = g[id][i]; }
        else if (g[id][i] > tmp2) tmp2 = g[id][i];
    }
    for (vector<int>::iterator it = ans1.begin(); it != ans1.end(); it ++) {
        int u = *it;
        tmp2 = max(tmp2, g[id][u]);
    }
    return tmp2;
}

bool cmp1(int a, int b) {
    return get_company(a) > get_company(b);
}

bool cmp2(int a, int b) {
    int sz = ans1.size();
    int tmp1 = 0, tmp2 = 0;
    for (int i = 0; i < sz; i ++) {
        tmp1 = max(tmp1, g[ ans1[i] ][a]);
        tmp2 = max(tmp2, g[ ans1[i] ][b]);
    }
    return tmp1 > tmp2;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        for (int j = i+1; j <= n; j ++) {
            cin >> g[i][j];
            g[j][i] = g[i][j];
        }
    }
    for (int i = 1; i <= n; i ++) vec.push_back(i);
    for (int i = 1; i <= n; i ++) {
        if (i % 2) {
            sort(vec.begin(), vec.end(), cmp1);
            ans1.push_back(vec[0]);
            belong[ vec[0] ] = 1;
            vec.erase(vec.begin());
        }
        else {
            sort(vec.begin(), vec.end(), cmp2);
            ans2.push_back(vec[0]);
            belong[ vec[0] ] = 2;
            vec.erase(vec.begin());
        }
    }
    int res1 = 0, res2 = 0;
    for (int i = 0; i < n/2; i ++)
        for (int j = i+1; j < n/2; j ++) {
            res1 = max(res1, g[ ans1[i] ][ ans1[j] ]);
            res2 = max(res2, g[ ans2[i] ][ ans2[j] ]);
        }
    // puts(res1 >= res2 ? "1" : "0");
    // if (res1 >= res2) cout << res1 << endl;
    puts("1");
    cout << res1 << endl;
    return 0;
}

著者:zifeiy

おすすめ

転載: www.cnblogs.com/codedecision/p/11710636.html