119 条题解

  • 2
    @ 2016-11-13 21:16:41

    本题可以
    ###***贪心***。
    按照贪心的指导思想,我们要求写每篇论文的时间最短。
    1.大概做法:我们可以通过YY之后求出 写每篇论文的时间,然后将他们进行**排序**,然后取**前n个**相加即可。
    2.求每篇论文的时间的方法如下:
    i. 比如说对于 第1个课题
    第1篇:a1*(1^b1),第2篇:a1*( (2^b1) - (1^b1) ) …… 第n篇:a1*( (n^b1) - ( (n-1)^b1 ) )。
    ii. 对于所有的m个课题,我们可以用O(n*m)的时间预处理出写每篇论文的时间。
    ###***重要的在这里↓***
    3.那么我们如何证明我们的做法是合法的呢?
    因为若我们选择写某一个课题的第i篇论文,那么这个课题的第1~i-1篇论文都必须被选择,换句话说,写的是前i篇论文。
    粗略证明如下:
    i.引理:2.i 中我们求得的 第n篇论文所花时间 的表达式** a*( n^b - (n-1)^b ) ** 对于所有的整数n≥1是一个***单调递增***数列。(大家可以通过数学方法证明,也可打表观察,反正当时是YY出来的,后来才去证明)
    ii.从1 中我们得到了一个**有序**的序列(递增),对于序列中第i个元素,前i-1个元素必然小于它,用题目中信息来解释:第i个元素代表了写**某一篇**论文所用的时间,前i-1个元素代表 所有 花的时间少于(等于)这一篇论文的论文所用的时间。
    假设这一篇论文为课题**j**的第***k***篇论文,那么根据引理,我们得知在上述有序序列的前***i-1***项中,必然包含了课题**j**的前***k-1***篇论文(因为它们所用的时间一定比第***k***篇论文短)。
    iii.至此,我们证明了这个做法的正确性。
    4. 预处理加上排序,这个算法的时间复杂度为O(m*n * lg(n*m) )。
    5. 若牛X的人可以用堆优化,使得总时间复杂度为O(n*lg(m))。具体原理及实现本文不再赘述。

    在此附上AC代码:
    ###block code
    ```
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int n, m, a, b;
    long long s[25 * 200], ans;
    long long power(int x, int y) {
    long long res = 1, tmp = x;
    while (y) {
    if (y & 1) res *= tmp;
    tmp *= tmp;
    y >>= 1;
    }
    return res;
    }

    int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++) {
    scanf("%d%d", &a, &b);
    for (int j = 0; j < n; j++) s[i * n + j] = a * (power(j + 1, b) - power(j, b));
    }
    //nth_element(s, s+n, s+m*n);
    sort(s, s + n * m);
    ans = 0;
    for (int i = 0; i < n; i++) ans += s[i];
    printf("%lld\n", ans);
    return 0;
    }
    ```

  • 1
    @ 2020-05-15 22:44:38

    //本来思路乱七八糟,想先试一下,下一个测试点再来写的,没想到直接就A了。

    //因为本人菜鸡所以适合新手理解

    上代码:

    #include<bits/stdc++.h>
    using namespace std;
    long long f[21][300],n,m,j,k,A[210],B[210],sum[10000],ans=0;
    //f[a][b]意思是前a个课题写b篇的最大值 
    int main()
    {
        long long int p,a,b,c,d,e;
        cin>>m>>n;
        for(a=1;a<=n;a++)cin>>A[a]>>B[a];//输入不解释
        for(a=1;a<=n;a++)//前a个课题
        {
            for(b=1;b<=m;b++)//选b篇写
            {
                for(c=0;c<=b;c++)//1.见下
                {
                    p=A[a]*pow(c,B[a]);//当前的值
                    if(f[a][b]==0||a==1)f[a][b]=f[a-1][b-c]+p;
                    else//因为当f[a][b]初始赋值或a=1需要特判
                    f[a][b]=min(f[a-1][b-c]+p,f[a][b]);//状态转移
                }
            }
        }
        cout<<f[n][m];
    }
    

    在第a篇中写0篇 f[a][b]=min(f[a-1][b]+p,f[a][b])//p见代码

    在第a篇中写1篇 f[a][b]=min(f[a-1][b-1]+p,f[a][b])

    在第a篇中写2篇 f[a][b]=min(f[a-1][b-2]+p,f[a][b])

    在第a篇中写c篇 f[a][b]=min(f[a-1][b-c]+p,f[a][b])

    因为已经保证前面的数组都是最大值,所以就是判断在a中选篇数再加上

    前一篇文章a-c的最大值。

  • 1
    @ 2016-01-29 11:35:40

    注意数据类型用long long,我用了int wa了三次= =

  • 0
    @ 2017-12-09 22:27:54

    一定要记得用long long!!!

  • 0
    @ 2017-01-22 15:58:56

    //神奇的程序
    ```C++
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <limits>
    using namespace std;

    struct node1
    {
    int a,b;
    }a[21];

    int main()
    {
    int n,m;
    double c[21][201],f[21][201];
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
    scanf("%d%d",&a[i].a,&a[i].b);
    for (int j=1;j<=n;j++)
    c[i][j]=double(a[i].a)*pow(double(j),double(a[i].b));
    }
    memset(f,0,sizeof(f));
    for (int i=0;i<=m;i++)
    for (int j=1;j<=n;j++)
    f[i][j]=(numeric_limits<double>::max)();
    for (int i=1;i<=m;i++)
    for (int j=1;j<=n;j++)
    {
    f[i][j]=min(f[i][j],f[i-1][j]);
    for (int k=1;k<=j;k++)
    f[i][j]=min(f[i][j],f[i-1][j-k]+c[i][k]);
    }
    printf("%.0lf\n",f[m][n]);
    }
    ```

  • 0
    @ 2016-11-21 19:50:03

    ××sdgsfg××

  • 0
    @ 2015-08-02 18:14:02

    program a1198;
    var
    i,j,k,l,n,m,ii,jj:longint;
    a,b:array[0..200]of int64; kk,ll:int64;
    f:array[0..100,0..2000]of int64;
    function he(x,y:longint):int64;
    var
    p:longint; q:int64;
    begin
    q:=1;
    for p:=1 to y do
    q:=q*x;
    he:=q;
    end;
    begin
    //assign(input,'1.txt'); reset(input);
    readln(n,m);
    for i:=1 to m do
    readln(a[i],b[i]);
    for i:=1 to n do
    f[1,i]:=a[1]*he(i,b[1]);
    for i:=2 to m do
    for j:=1 to n do
    begin
    kk:=maxlongint;
    for k:=0 to j do
    begin
    ii:=j-k;
    ll:=f[i-1,k]+a[i]*he(ii,b[i]);
    if (ll<kk) then kk:=ll;
    end;
    f[i,j]:=kk+f[i,j];
    end;
    writeln(f[m,n]);
    end.

  • 0
    @ 2015-08-01 22:58:11

    都是pow函数惹的祸啊!!!
    Wrong Answer:
    ###
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;

    #define MAX 2147483647

    int n, m;
    int f[25][20005];

    int main(int argc, const char *argv[])
    {
    for (int i = 0; i <= 20; ++i)
    for (int j = 0; j <= 40000; ++j)
    f[i][j] = MAX;
    f[0][0] = 0;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; ++i)
    {
    int a, b;
    scanf("%d %d", &a, &b);
    for (int j = 0; j <= n; ++j)
    {
    int min = MAX;
    for (int k = 0; k <= j; ++k)
    {
    long long p = (long long)(f[i - 1][j - k]) + a * (long long)(pow(k, b));
    if (p < (long long)(min))
    min = (int)p;
    }
    f[i][j] = min;
    }
    }
    printf("%d\n", f[m][n]);
    return 0;
    }

    Accepted:
    ###
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;

    #define MAX 2147483647

    int n, m;
    int f[25][20005];

    long long val(long long k, long long b)
    {
    long long ans = 1;
    for (int i = 1; i <= b; ++i)
    ans *= k;
    return ans;
    }
    int main(int argc, const char *argv[])
    {
    for (int i = 0; i <= 20; ++i)
    for (int j = 0; j <= 40000; ++j)
    f[i][j] = MAX;
    f[0][0] = 0;
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; ++i)
    {
    int a, b;
    scanf("%d %d", &a, &b);
    for (int j = 0; j <= n; ++j)
    {
    int min = MAX;
    for (int k = 0; k <= j; ++k)
    {
    long long p = (long long)(f[i - 1][j - k]) + a * (long long)(val(k, b));
    if (p < (long long)(min))
    min = (int)p;
    }
    f[i][j] = min;
    }
    }
    printf("%d\n", f[m][n]);
    return 0;
    }

  • 0
    @ 2015-06-11 08:45:13

    我只想说,注意数据范围。。。

  • 0
    @ 2015-01-22 23:04:56

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define MAXL 10001

    long long dp[MAXL], V, n, w, a, b;
    long long value(long long a, long long k, long long b);

    int main()
    {
    cin >> V >> n;
    for (int i = 1; i <= n; i++)
    {
    cin >> a >> b;
    if (i == 1)
    {
    for (int i = 1; i <= V; i++)
    dp[i] = value(a, i, b);
    continue;
    }
    for (int j = V; j >= 1; j--)
    for (int k = 1; k <= V; k++)
    dp[j] = min(dp[j - k] + value(a, k, b), dp[j]);

    }
    cout << dp[V] << endl;
    }

    long long value(long long a, long long k, long long b)
    {
    long long x = 1;
    for (int i = 0; i < b; i++)
    x *= k;
    return x * a;
    }


    数据很小?自己算一下就知道有多大了。全程用longlong才AC。。。
    这题就是一个很标准的分组背包,连程序都跟模板差不多。。。

  • 0
    @ 2014-11-01 11:31:58

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    using namespace std;

    struct topic{LL A,B;}t[25];

    LL n,m,f[25][205];

    LL Pow(LL a,LL b)
    {
    LL Ans=1;
    while(b)
    {
    if(b%2) Ans=Ans*a;
    a*=a;
    b/=2;
    }
    return Ans;
    }

    int main()
    {
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    cin>>t[i].A>>t[i].B;
    memset(f,0x7f7f7f7f,sizeof(f));
    for(LL i=0;i<=n;i++)
    f[1][i]=t[1].A*Pow(i,t[1].B);
    for(int i=2;i<=m;i++)
    for(int j=0;j<=n;j++)
    for(int k=0;k<=j;k++)
    f[i][j]=min(f[i][j],f[i-1][j-k]+t[i].A*Pow(k,t[i].B));
    cout<<f[m][n]<<endl;
    return 0;
    }

  • 0
    @ 2014-11-01 11:16:50

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    using namespace std;

    struct topic{LL A,B;}t[25];

    LL n,m,f[25][205];

    LL Pow(LL a,LL b)
    {
    LL Ans=1;
    while(b)
    {
    if(b%2) Ans=Ans*a;
    a*=a;
    b/=2;
    }
    return Ans;
    }

    int main()
    {
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    cin>>t[i].A>>t[i].B;
    memset(f,0x7f7f7f7f,sizeof(f));
    for(LL i=1;i<=n;i++)
    f[1][i]=t[1].A*Pow(i,t[1].B);
    for(int i=2;i<=m;i++)
    for(int j=1;j<=n;j++)
    for(int k=1;k<=j;k++)
    f[i][j]=min(f[i][j],f[i-1][j-k]+t[i].A*Pow(k,t[i].B));
    cout<<f[m][n]<<endl;
    return 0;
    }

  • 0
    @ 2014-08-22 13:36:58

    ##思路##

    \(dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + Cal(i, k))\)

    dp[i][j]表示前i个主题写j篇论文的最少时间。

    初始化要注意。
    刚开始全部初始化为INF,WA了。有论文数是0的数据。

    ##代码##

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int MAXN = 200 + 5;
    const int INF = 0x3f3f3f3f;
     
    struct ARTC
    {
        LL a, b;
    }artc[MAXN];
     
    LL dp[30][MAXN];
     
    LL Cal(LL cur, LL num)
    {
        LL t = 1;
        for (int i = 0; i < artc[cur].b; i++)
            t *= num;
        return t * artc[cur].a;
    }
     
    int main()
    {
        //freopen("input.txt", "r", stdin);
        LL ntopc, npp, i, j;
        scanf("%lld%lld", &npp, &ntopc);
        for (i = 1; i <= ntopc; i++)
            scanf("%lld%lld", &artc[i].a, &artc[i].b);
        for (i = 1; i <= ntopc; i++)
            for (j = 1; j <= npp; j++)
                dp[i][j] = INF;
        for (i = 1; i <= npp; i++)
            dp[1][i] = Cal(1, i);
        for (i = 2; i <= ntopc; i++)
            for (j = 1; j <= npp; j++)
            {
                dp[i][j] = dp[i - 1][j];
                for (LL k = 1; k <= j; k++)
                    dp[i][j] = min(dp[i][j], dp[i - 1][j - k] + Cal(i, k));
            }
        printf("%lld\n", dp[ntopc][npp]);
        return 0;
    }
    
  • 0
    @ 2014-02-23 11:14:14

    #include<cstdio>
    #include<iostream>
    using namespace std;
    long long int A[100][201];
    long long int c[100];
    long long int d[100];
    long long int jisuan(long long int ci,long long int i,long long int di)
    {
    long long int temp = 1;
    for (long long int k = 1; k <= di; k++)
    temp = temp * i;
    return temp * ci;
    }
    long long int xiao(long long int a,long long int b)
    {
    if(a>b)
    return b;
    else
    return a;
    }

    int main()
    {
    long long int n,m;
    long long int i,j,k;
    cin>>n>>m;
    for(i=1;i<=m;i++)
    {
    cin>>c[i]>>d[i];
    for(j=1;j<=m;j++)
    {
    A[i][j]=999999999;
    }
    }
    A[0][0]=0;

    for(i=1;i<=n;i++)
    {
    A[1][i]=jisuan(c[1],i,d[1]);
    }
    for(i=2;i<=m;i++)
    {
    for(j=1;j<=n;j++)
    {
    A[i][j]=A[i-1][j];
    for(k=1;k<=j;k++)
    {
    A[i][j] = xiao(A[i][j], A[i-1][j-k]+jisuan(c[i], k, d[i]));
    }
    }
    }
    cout<<A[m][n];
    return 0;
    }

  • 0
    @ 2014-01-01 12:00:47

    Vijos 题解:http://hi.baidu.com/umule/item/2c997f8ed9600fdae596e017
    有疑问请留言 共同进步

  • 0
    @ 2013-11-06 09:51:47

    var
    a,b:longint;
    i,j,k,n,m:longint;
    v:array[1..200,1..2000] of int64;
    f:array[0..2000] of int64;
    begin
    readln(n,m);
    for k:=1 to m do
    begin
    readln(a,b);
    for i:=1 to n do
    begin
    v[k,i]:=a;
    for j:=1 to b do
    v[k,i]:=v[k,i]*i;
    end;
    end;
    f[0]:=0;
    for i:=1 to n do
    f[i]:=maxlongint;
    for k:=1 to m do
    for i:=n-1 downto 0 do
    for j:=1 to n-i do
    if (f[i]+v[k,j]<f[i+j]) then f[i+j]:=f[i]+v[k,j];
    writeln(f[n]);
    end.

  • 0
    @ 2013-11-03 18:22:10

    //const
    // ma=;
    var
    fa,wei,v,a,b,f:array[0..40000]of int64;
    ss,t,w,m,n,x,s:int64;
    i,j,k:longint;
    function min(x,y:int64):int64;
    begin
    if x<y then min:=x else min:=y;
    end;
    begin
    assign(input,'choose.in');
    assign(output,'choose.out');
    reset(input);
    rewrite(output);

    readln(n,m);
    for i:=1 to m do
    readln(a[i],b[i]);
    for i:=1 to m do
    for j:=1 to n do
    begin
    x:=1;
    for k:=1 to b[i] do
    x:=x*j;
    x:=x*a[i];
    ss:=ss+1;
    wei[ss]:=j;
    v[ss]:=x;
    fa[ss]:=i;
    end;
    w:=0;
    fillchar(f,sizeof(f),127);
    f[0]:=0;
    for i:=1 to m do
    begin
    t:=w+1;
    w:=ss;
    for j:=t+1 to ss do
    if fa[j]<>fa[t] then
    begin
    w:=j-1;
    break;
    end;
    for j:=n downto 1 do
    for k:=t to w do
    if j>=wei[k] then
    f[j]:=min(f[j],f[j-wei[k]]+v[k]);
    end;
    writeln(f[n]);

    close(input);
    close(output);
    end.
    分组背包

    • @ 2013-11-03 18:22:48

      120题 庆祝一下

  • 0
    @ 2013-10-17 21:31:11

    过掉了一题很爽的题目!
    想了十多分钟,总算有点思路,并一次AC了。
    我个人认为这题为背包,不太恰当。
    思路:我们可以设f[i,j]表示在第i个课题,结尾为第j篇论文的最小价值。
    而新的状态f[x,y]:=min(f[x,y],f[i,j]+num(y-j,x));
    num是一个专门计算y-i这几篇论文,全部用于x课题时,算出答案。
    一共四重循环,卡着时间AC。。。
    最后答案就在min(f[i,n]),i循环一边即可。
    注意要用int64;
    也看了下面几位大牛关于背包的题解,不太理解。虽然我的算法实现时间很丑,但是能过就行把!
    DXE-SYF。
    Go on!

  • 0
    @ 2013-07-21 14:00:05

    忽略算法 这个题主要有两个地方需要注意
    1.初始化 初始化我们可以用第一个数据A[1]和B[1]来进行初始化,设Dp[i]表示写到第i篇论文时最少的时间数,初始化的时候可以令Dp[i]=A[1]*i^B[i],这样就不需要初始化成INF(一个接近于无穷大的数)
    2.数组要大 题目当中说的n<=200,m<=20, 我严重怀疑这个真实性 当我把Dp开到1200个数时才过的

    P.S.真是不好意思,为这道题贡献了太多太多的WA。。。以上。。。

信息

ID
1198
难度
6
分类
动态规划 | 背包 点击显示
标签
(无)
递交数
2862
已通过
844
通过率
29%
被复制
4
上传者