タンクのCodeForces - 920D(DP)

ペチャは時々彼のフィールドに水を持っています。フィールドを水、ペチャは水の正確V mlのタンクを必要とします。

ペチャは、彼らが最初に含むのi番目ミリリットルの水をAI、Nタンクを持っています。タンクは、それらのいずれかが、水の任意の量(この量がどのように大規模に関係なく)を含むことができ、本当に大きいです。

また、ペチャは、水のKミリリットル(最初にスクープが空である)まで含めることができますスクープを持っています。このスクープは、いくつかのタンクからいくつかの水を得るために使用され、その後(それを注ぐことなく、複数のタンクから水を得る、またはそれを注ぐ時にスコップでいくつかの水を残すことは不可能である)、すべてのいくつかのタンクにそれを注ぐことができます。ペチャがタンクからいくつかの水を取得しようとすると、彼はvは、タンク内の水の現在のボリュームである分(V、K)水を、取得します。

これらの操作を用いて水の正確V mlのタンクを取得することが可能ですか?それが可能である場合は、それを行うことを可能にする一連の操作を印刷します。いくつかのタンク内の水の必要な量を得るために複数の方法がある場合は、それらのいずれかを印刷します。

入力
-タンクの数、水の最大量スクープに含めることができるN(2≤N≤5000)、K(1≤K≤5000)、およびV(0≤V≤109):最初の行は、3つの整数を含みます、それぞれ、いくつかのタンク内の水の量を必要としました。

2行目は、(0≤≤105 AI)aiをN個の整数を含む場合aiはi番目のタンク内の水の初期量です。

出力は
、それが水の正確V mlのタンクを得ることができない場合は、NOを印刷します。

そうでない場合は最初の行でYESを印刷する、2行目から始めて、次の形式の動作のシーケンスを印刷。

「CNT XY」(1≤CNT≤109、1≤x、y≤N)xは、yは指数我​​々は水を得るタンクの指標である:各ラインは、圧縮動作を表す3つの数字を含んでいなければなりません我々は水を注ぐタンク、およびCNTは、我々はタンクyにタンクxから水を移送する回数です。

これらの行の数は、N + 5を超えてはなりません。


インプット
2 3 5
2 3
出力
YES
1 2 1
入力
2 3 4
2 3
出力
NO
入力
5 2 0
1 3 5 7 9
の出力
YES
2 2 1
3 3 1
4 4 1
5 1

します。https://www.cnblogs.com/kkkkahlua/p/8413054.htmlソース考える
質問の意味:
あなたはn個の池を持っていますが、一定量の水と無限大のボリュームがあります。Kは、スプーンの体積であり、プール分(K [i]を保持することができる ) 他のタンクに水を。水のV量の分布かどうかを調べます。
アイデアは:
まず、カウントモジュロkにデジタルに変換されます。
Jのi番目の前の池の水ディスペンサーの実現可能性のためにF. [I] [j]を定義します。
F. [I] [J] =
0 -実行不可能
1--可能で、必ずしもそうではない[I]との
2 -可能と[I]を使用する必要があります

だから、これで我々は体積Vかどうかを確認することができ、そして逆推力の結果から引き出されたもので、何必ずしも使用したいされていないを使用する必要があります。

合計{[I]]}またはDP [n]が[V%K] = 0の場合、確かではありません。

あなたが使用する必要がない場合は、Vは、kの倍数でなければならない、すべての水一緒に、V / kはうまく水の中からスプーンを追加
それ以外の場合は、すべての水がS1と一緒に入れて使用する必要がありません私たちは、S2と水を一緒に使用する必要があります。次いで間隙S1及びVは、kの倍数、プラス(マイナス)は、複数の微細でなければなりません。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int a[5005],b[5005],dp[5005][5005];
int flag[5005];

int main()
{
    int n,k,v;scanf("%d%d%d",&n,&k,&v);
    int sum = 0;
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&a[i]);
        b[i] = a[i];a[i] %= k;
        sum += b[i];
    }
    
    if(sum < v)
    {
        printf("NO\n");
        return 0;
    }
    dp[0][0] = 1;
    for(int i = 1;i <= n;i++)
    {
        for(int j = 0;j < k;j++)
        {
            if(dp[i - 1][j])
            {
                dp[i][j] = 1;
                if(!dp[i][(j + a[i]) % k])dp[i][(j + a[i]) % k] = 2;
            }
        }
    }
    int num = v % k;
    if(!dp[n][num])
    {
        printf("NO\n");
        return 0;
    }
    printf("YES\n");
    
    int x1 = -1,x2 = -1,ans = 0;
    
    for(int i = n;i >= 1;i--)
    {
        if(dp[i][num] == 2)
        {
            flag[i] = true;
            num = (num - a[i] + k) % k;
            ans += b[i];
            if(x1 == -1)x1 = i;
        }
        else if(x2 == -1)x2 = i;
    }
    if(x1 == -1)//没有一定要添加的,那就是添加任何一个都可以,那v一定是k的倍数
    {
        for(int i = 1;i < n;i++)
        {
            if(b[i])
            {
                printf("%d %d %d\n",(b[i] + k - 1) / k,i,n);
            }
        }
        if(v / k)printf("%d %d %d\n",v / k,n,1);
        return 0;
    }
    
    int res = v - ans;
    int s1 = b[x1],s2 = b[x2];
    for(int i = 1;i <= n;i++)
    {
        if(i == x1 || i == x2 || !b[i])continue;
        if(!flag[i])
        {
            printf("%d %d %d\n",(b[i] + k - 1) / k,i,x2);//非必要的全部放到x2
            s2 += b[i];
        }
        else
        {
            printf("%d %d %d\n",(b[i] + k - 1) / k,i,x1);//必要的全部放到x1
            s1 += b[i];
        }
    }
    int cnt = (v - s1) / k;
    if(cnt > 0)printf("%d %d %d\n",cnt,x2,x1);//此时x1与v的差一定是k的倍数
    else if(cnt < 0)printf("%d %d %d\n",-cnt,x1,x1 == 1 ? 2 : 1);
    return 0;
}


公開された676元の記事 ウォン称賛18 ビュー30000 +

おすすめ

転載: blog.csdn.net/tomjobs/article/details/104241859