zoukankan      html  css  js  c++  java
  • POJ 1722 SUBTRACT

    给定一个数组a[1,2,..,n] 。定义数组第i位上的减操作:把ai和ai+1换成ai - ai+1。输入一个n位数组以及目标整数t,求一个n-1次操作序列,使得最后剩下的数等于t
    最后输出依此操作的i

    输入:第一行一个N,一个T,接下来N行,每行一个正整数ai
    输出:依次输出被操作的位置i

    首先对题目进行分析后,似乎没有什么好的思路。
    从结果入手。
    对于最后的得到的整数,肯定是将原数列中一些数前加上了符号,然后将数列加在一起的操作。
    这样我们就避免了麻烦的数组操作。‘

    这样我们将题目转换成了:
    一个数列[a1, a2, ....aN],对于数组中的数,将部分正整数变为负数,使整个数组的和为t,最后输出将哪些数变为负数
    其中,从原题中我们可以知道:由于第1个数前没有数,所以第1个数不可能加负数,这样我们想,假设最后剩下两个数a1, a2,由原题目我们知道,要想把这两个数化为一个整数,第二个数必须为负数。
    因此,在最初,第一个数必须为正,第二个数必须为负数。

    然后整理能够描述状态空间的信息:
    1.一个正整数i,表示进行到了第i个数
    2.标记-1或1,表示第i个数取负还是取正
    3.一个整数,表示进行到第i个数时,前i个数的和

    接着我们要确定的是第i个数取正还是取负,然后我们还需要前i-1个数的和,但是我们能够注意到的是,前i-1个数的和是不确定的,对于i前的除了1,2位置的数,每一个数都有取正和取负两个操作,由于i可能很大
    因此前i-1个数的和的结果也很多,所以对于i-1个数的和是不确定的,而对于第i个数取正还是取负,一共只有两个情况。
    这样我们只能将前i-1个数的和作为变量,加一个维度,用来描述状态空间。
    设f[i, j] = k表示到第i个数,前i个数的和为j时,第i个数的标记为k
    这样问题的重点就在于如何记录路径了
    对于我们的思路肯定是倒推回去
    我们试着从f[][t]推回去
    但是对于第一维,我们是并不确定的,
    我们只能试着将i从2到n一个一个搜,但是注意的是i不能从1开始,最后我们处理1时再说原因
    我们从我们的策略分析:我们可以发现,我们首先需要输出的显然是一路倒推后标记为1的i值,但是我们有一点就是我们每操作一个i,i之后的数的下标会全部减1。
    因此首先我们首先要从答案一路逆推回去,同时开一个新数组,在第i个位置标记这个数是取正还是取负。
    然后首先输出所有标记取正的下标,但是我们知道一个操作结束后后面的下标会变,所以我们设一个新的变量记录在某个位置之前操作了多少次,例如:我们设我们现在第i个位置,前面操作了cnt次,这样i的下标就应该因为操作而被迫变更了cnt次,但是观察样例的推断我们可以发现,在样例中,原本i = 2时,i = 2理当是正的,但是在最初我们全部将i = 2的情况标记为负了,所以这就是说,类推到所有情况,所有取正的下标,在原题i和i+1的
    情况中,实际上取正的是i+1,所以对于取正的位置的下标,除了要减去cnt外,还要再减去1
    最后我们讨论输出1的情况,我们相当我们吧所有取正的情况输出后,操作次数cnt,很可能(很大可能)并不到n-1,一方面是因为刚才我们没有输出1,但另一方面,存在cnt与n-1的差距不止1,这种情况说明在最后,在进行了全部的操作后,最后所有剩下的数不再进行取正操作,也就是说除了1之外全部取为了负数,例如: 1 2 3 4 5 6 ,除了1之外,2,3,4,5,6全部标成取负号,这意味着在这些操作中,所有的i全部取为1,所以我们就要输出
    n-1-cnt个1,当然也可以是在所有在标记为取负的位置输出'1',但是我们上面说了因为2的符号强制取负的关系,下标除了减去cnt还要再减去1,但是1是不受影响的,原因非常简单:下标1在下标2之前,所以下标1不受下标2的影响

    最后顺便批判一番!AC程序过不了样例系列!!!!!!

     1 #include<iostream>
     2 #include<iomanip>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<ctime>
     7 #include<cstdlib>
     8 #include<cmath>
     9 using namespace std;
    10 const int maxn = 105;
    11 const int maxt = 20086;
    12 const int quz = 10005;
    13 int n, t;
    14 int f[maxn][maxt];
    15 int a[maxn];
    16 int ans[maxn];
    17 
    18 inline int read() {
    19     int x = 0, y = 1;
    20     char ch = getchar();
    21     while(!isdigit(ch)) {
    22         if(ch == '-') y = -1;
    23         ch = getchar();
    24     }
    25     while(isdigit(ch)) {
    26         x = (x << 1) + (x << 3) + ch - '0';
    27         ch = getchar();
    28     }
    29     return x * y;
    30 }
    31 
    32 int main() {
    33     memset(f, 0, sizeof(f));
    34     n = read(), t = read();
    35     for(int i = 1; i <= n; ++i)
    36         a[i] = read();
    37      f[1][a[1] + quz] = 1;
    38      f[2][a[1] - a[2] + quz] = -1;
    39      for(int i = 3; i <= n; ++i)
    40          for(int j = -10000 + quz; j <= 10000 + quz; ++j) {
    41              if(f[i - 1][j] != 0) {
    42                  f[i][a[i] + j] = 1;
    43                  f[i][j - a[i]] = -1;
    44              }
    45          }
    46     int s = quz + t;
    47     for(int i = n; i >= 2; --i) {
    48         ans[i] = f[i][s];
    49         if(ans[i] == 1)
    50             s -= a[i];
    51         else if(ans[i] == -1) 
    52             s += a[i];
    53     }
    54     int cnt = 0;
    55     for(int i = 2; i <= n; ++i)
    56         if(ans[i] == 1) {
    57             cout << i - cnt - 1 << '
    ';
    58             cnt++;
    59         }
    60     for(int i = 2; i <= n; ++i) 
    61         if(ans[i] == -1)
    62             cout << 1 << '
    ';
    63 /*    for(; cnt + 1 <= n - 1; cnt++) 
    64         cout << 1 << '
    ';*/
    65     return 0;
    66 }

     

  • 相关阅读:
    第二周之Hadoop学习(二)
    Java课程----自我介绍
    关于最大子序和的算法问题
    记账本----完结
    《人月神话》读后感----四
    记账本----四
    记账本----四
    《人月神话》读后感------三
    记账本------三
    家庭记账本----二
  • 原文地址:https://www.cnblogs.com/ywjblog/p/9252394.html
Copyright © 2011-2022 走看看