NOIPシミュレーション演習7

NOIPシミュレーション演習7

  • 300のうち、私は20ポイントを持っています。補正後の300ポイント。
  • 難易度:簡単。
  • 概要:固体、簡単な質問すべき基本的なスキルポイントを削除することはできません。
  • 一人当たりAK QAQ。あなたは長いスナックバーの詳細華を書くことができます!

脂肪のメカニック

説明

  • 我々は、すべての脂肪は機械エンジニアであることを知って、彼は、脂肪だったが、最近はジレンマに遭遇しました

    この事はとても自分の体重を20%に低下したことを気にされます!

    薄いマシンの3D設計図面に脂肪を悩まからのデザイナーは、細いはそうではありません

    強度、図面はぼやけ描いたが、これは実際には正方形のマシンではないことを、他のワーク外気

    ビット脂肪800度のビジョンは厳しくテストされるので、彼は食べ物を飲み込むていない彼の時間を費やしています。

    太った男は最終的に立つことができなかった、私は、最新の技術に頼ることにしました - コンピュータは、彼はLenovoのコンピュータを買って、

    、報酬として肉1キロを持つので、脂肪それは区別するために、描画が、あなたのコンピュータにそのようなソフトウェアが存在しないと、

    私はあなたが彼がソフトウェアの設計を支援願っています。

    脂肪男は言った:「私の図面は、三次元(高度バール)であり、座標系グリッドによって分割、各片が含まれてい

    グリッドのいくつかの隣接部分、薄い人々の悪は愚かであるため、私はぼかし差で考える必要があります

    二つの隣接するセルの範囲を考えると、同じワークです、あなたは私がそれのワークの合計数を見つけるのに役立ちます。」

入力

  • (H <= 50、W L、)H、W 3の整数Lの最初の行は、長さと幅の3次元描画を表します。

    整数m(0 <= M <= 255)の第2行は、ブレ差の最大許容度を表します。

    Lライン続いW小から大へ、0から255までH非負整数は、各薄いビデオの空間座標に応じて与えられます。

    ぼかしグリッド(長さ、幅、高優先度に応じて、座標の大きさを比較されたいです)。

出力

  • ワークの整数。

サンプル入力

2 2 2

0

1 1 1 1 2 2 2 2

サンプル出力

2

ソリューション:

  • 検索。
  • 検索は、ユニコム3次元ブロックを探します。
#include <iostream>
#include <cstdio>
#include <cmath>
#define N 55
using namespace std;

int x, y, z, avg, ans;
int a[N][N][N]; //第一维是横切(),第二维是竖切,第三维是立切
bool vis[N][N][N];
int dx[7] = {0, 0, 0, 0, 0, -1, 1};
int dy[7] = {0, 0, 0, -1, 1, 0, 0};
int dz[7] = {0, 1, -1, 0, 0, 0, 0};

int read()
{
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x;
}

void dfs(int v1, int v2, int v3)
{
    for(int i = 1; i <= 6; i++)
    {
        int xx = v1 + dx[i], yy = v2 + dy[i], zz = v3 + dz[i];
        if(xx < 1 || xx > x || yy < 1 || yy > y || zz < 1 || zz > z) continue;
        if(vis[xx][yy][zz]) continue;
        if(abs(a[xx][yy][zz] - a[v1][v2][v3]) <= avg)
        {
            vis[xx][yy][zz] = 1;
            dfs(xx, yy, zz);
        }
    }
}

int main()
{
    cin >> x >> y >> z >> avg;
    for(int i = 1; i <= x; i++)
        for(int j = 1; j <= y; j++)
            for(int k = 1; k <= z; k++)
                a[i][j][k] = read();
    for(int i = 1; i <= x; i++)
        for(int j = 1; j <= y; j++)
            for(int k = 1; k <= z; k++)
                if(!vis[i][j][k])
                {
                    ans++;
                    vis[i][j][k] = 1;
                    dfs(i, j, k);
                }
    cout << ans;
    return 0;
}

チェス盤カバレッジ

説明

  • 1と1と1 2二種類の正方形からなる板により2 * Nドミノカバーするために、複数の方法が存在することができます

    ケースは、図は、N = 1を示し、N = 2は、2つのチェッカーボード方式を覆い、「■」はドミノ1を表し、「■■」* 1を表します

    ドミノ2、それは見ることができ、ボードは2 2 * 1コート法、ボードを2 * 2が7コーティング法をしています。

入力

  • Chess.in入力ファイルは、ただ1つの行は、整数N、1≤N≤30の正の値が与えられ、データの50%

    1≤N≤15。

出力

  • Chess.outものみ、出力ファイルの1行は、ドミノの2 Nチェスカバー1112及び二種類によって与えられます。

    プログラムディスクの合計数。

サンプル入力

2

サンプル出力

7

ソリューション:

  • DP。
  • ねえ、私は本当にこの問題肯定的な解決策について考えていませんでした。主な理由は、それが考える参照するには、問題の地方選挙の悪夢。元のタイトルのように見えるので、スキップさ... ...

  • 実際には、この質問は、真剣に、通常のDPああだと思います!
  • 4例以下、どのように新たに追加された操作考えてみましょう:
    1. フラットフロント
    2. 第1の突起の前列は、第二行は平坦です
    3. 最初のラインを投影する第二行は平坦であり、前
    4. の突出の2つのフロントロー
  • 次いで、DP(I)(1/2/3/4)を算出ループのため。良い考えを転送します。

  • 矢印は、現在の行です。その後、矢印がフラットになるにするために、最初のケースを考慮し、最初のケースから転送することができ、林立2 1 * 1 * 1又は2個、その後DPフィル(I、1)+ = DP (I - 1、1)* 2。DP(I、1)+ = DP次いで、1 * 1レベルを満たすために2行目に、第二ケースから転送されてもよい(I - 1、2)。第三の場合、同じ理由から、DPから転送されてもよい(I、1)+ = DP(I - 1、3)。すでに結ばれているので、まあ記入しない、第4のケースから転送することができます。要約:DP(iは1)DP(I - 1、1)= * 2 + DP(I - 1、2)+ DP(I - 1、3)+ DP(I - 1、4)。
  • 現在の列、2行目平坦に突起の最初の行を作るために、第二のケースを考えます。これは、最初の3例から転送することができます。要約:DP(iは、2)= DPを(I - 1、1)+ DP(I - 1、3)。なぜ、2または4ケースからそらすことができないので、この行で一行だけの配慮関係!
  • 第三に、4例と同じ理由で、プッシュしないでください。次いで、最終的なDPは(N、1)も望まれています。
#include <iostream>
#include <cstdio>
#define int unsigned long long
using namespace std;

int n;
int f[35][5];

signed main()
{
    cin >> n;
    f[0][1] = 1;
    for(int i = 1; i <= n; i++)
    {
        f[i][1] = f[i - 1][1] * 2 + f[i - 1][2] + f[i - 1][3] + f[i - 1][4];
        f[i][2] = f[i - 1][1] + f[i - 1][3];
        f[i][3] = f[i - 1][1] + f[i - 1][2];
        f[i][4] = f[i - 1][1];
    }
    cout << f[n][1];
    return 0;
}

累積降水量

トピック:

ソリューション:

  • 検索/互いに素セット。
  • 爆発簡単に検索タイムアウトが、データは非常に小さい範囲にどのような質問。私の思考は、ばらばらのセットの最適化と直接計算されます。複雑さは、検索よりもはるかに高速O(NM + V)、です。
  • この質問のために、私たちは考える各層多くの水を保持することができます。和の合計が答えであることを最高レベルまでレベル0からこのような列挙。その答えは、どのようにそれの各層をカウントするには?我々は、点の高さ<= hとチャイナユニコムとの境界が、これは確かに耐えているので、もし層の現在の数(高さ)は、hであると仮定すると、ことを知っています。だから、列挙された各高さのために、高さは、4週間に拡大する点の位置を見つけます。周りの点の高さ<=さh、及び現在のポイントに、この時点までの場合。0最終的な答えと合併として(ノードとボーダー合併の数は、アクセスのこのレベルであるとみなすことができる-サイズは[getFat(0)] ..
#include <iostream>
#include <cstdio>
#include <vector>
#define N 105
using namespace std;

struct Node {int x, y;};
vector<Node> a[N * N];
int n, m, tot, h, ans;
int fat[N * N], size[N * N];
int dx[5] = {0, -1, 1, 0, 0},
    dy[5] = {0, 0, 0, -1, 1};
bool vis[N][N];

int read()
{
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x;
}

int getFat(int x)
{
    if(fat[x] == x) return x;
    return fat[x] = getFat(fat[x]);
}

void merge(int x, int y)
{
    int fx = getFat(x), fy = getFat(y);
    if(fx == fy) return;
    if(size[fx] > size[fy]) swap(fx, fy);
    size[fy] += size[fx], fat[fx] = fy;
}

int cal(int x, int y)
{
    if(x < 1 || x > n || y < 1 || y > m) return 0;
    return (x - 1) * m + y;
}

int main()
{
    freopen("water.in", "r", stdin);
    freopen("water.out", "w", stdout);

    cin >> n >> m;
    for(int i = 1; i <= n * m; i++)
        fat[i] = i, size[i] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            int val = read();
            h = max(h, val);
            a[val].push_back((Node){i, j});
        }
    /**
        * 这种一层一层看的思路就是我原先的思路,然后我写挂了。(爆搜
        * 但我没想到用并查集。枚举每一层高度,已知只要 <= 当前高度且与边界相连的点肯定
          会流走。所以用遍历到的点个数 - 这种类型的点个数就是当前层的答案。那么“这种
          类型”的点可以用并查集维护。
     */
    for(int i = 0; i <= h; i++) //这里必须要每个高度枚举到,因为这也是“一层水”
    {
        for(int j = 0; j < a[i].size(); j++)
        {
            int x = a[i][j].x, y = a[i][j].y;
            vis[x][y] = 1, tot++;
            for(int k = 1; k <= 4; k++)
            {
                int xx = x + dx[k], yy = y + dy[k];
                if(xx < 1 || xx > n || yy < 1 || yy > m) merge(cal(x, y), cal(xx, yy));
                if(vis[xx][yy]) merge(cal(x, y), cal(xx, yy));
            }
        }
        ans += tot - size[getFat(0)];
    }
    cout << ans;
    return 0;
}

おすすめ

転載: www.cnblogs.com/BigYellowDog/p/11370068.html