Cf 105 Div.2


全部1A的,orz——————————。




A题

D很小,直接for(i,1,D) 。


B题

追击问题。

我的做法:  while(1){ ... }    

最开始 int front= T * vp.  

那么 vd * times == front + vp* times; 算出times 然后判断是否有超过 dis,如果没有,则

front+  ( ( f + times + times ) * vp ). 进入下一循环。


C题

构造问题,这个题得细心了。

给定n,a,b,表示n个数字的序列,A类数有a个,B类数有b个,保证 n> a+b;

A类:   前面的数都小于该数;

B类:   前面所有数的和 小于 该数;

注意如果既是A类又是B类,那么该数算B类。

我的构造方法:

开始是1 ,然后先构造B类,2,4,8,16...然后构造A类。取B类的最后那个数+1. 然后逐个加1.最后有多余的全部取1.

比如 b=3,a=3,n=10 ==》

1  2  4  8  9 10 11 1 1 1.


注意了有一些特殊情况:

n=2, a=1,b=0:  你可能会写: 1 2,这是不对的。

n=3, a=2,b=0: 。。。。。。1 2 3,这是不对的。

n=4, a=2, b=0: 。。。。。。1 2 3 1,这是不对的,我的解决方法: 1 1 2 3。

所以 ==》if( b==0 && 3+a-1 > n )  则puts("-1");


D题

有点递推的意思,又有点博弈的味道,某个最终的局面由一个个子局面递推而来。

dp[ w ][ b ][ 0 ]: 面对 w个white,b个black的局面,轮到p来取的时候,  p最后赢的概率。

dp[ w ][ b ][ 1 ]: 面对 w个white,b个black的局面,轮到d来取的时候,  p最后赢的概率。

递推方程:

dp[ w ][ b ][ 0 ]=  w/(w+b) + b/(w+b)*dp[ w ][ b-1 ][ 1 ];

dp[ w ][ b ][ 1 ]:

考虑取w和取b两个情况,同时每个情况下考虑跳出的mouse是w的还是b的。代码比较简单。


E题

This problem involved dynamic programming with precalculation.

The first part of the solution was to precalculate the maximal cost of i items taken from the shelf (i ranging from 1 to the number of items on the shelf) for each shelf. Note that this can’t be done greedily: this can be seen on the shelf 6: 5 1 10 1 1 5.

The second part is a standard dynamic programming, which calculates the maximal cost of items taken for index of last shelf used and total number of items taken. To advance to the next shelf, one has to try all possible numbers of items taken from it and increase the total cost of items taken by corresponding precalculated values.

上面是 blog。

我的做法是 预处理每个row + 01背包。

对于每个row,假设有cnt个,需要得到取 j个 ( 1<=j<=cnt )个的最大值,那么做法是逆向dp,题目需要的是两边向中间取,所以

f[ i ]: 对于某行,连续长度为i的子段的最小值。那么总和sum-f[i]就是 取 cnt-i 个的最大值。

然后是01背包。复杂度O(n*m*100)。最终还是ac了,cf居然暴力也过了。其实我认为会超时的,题目数据弱。


然后是我问了问题,结果国外那位热心的大牛回答了: 10000*10000= 100000000,8个0,不会超时。。。



表示差点忘记01背包了。

/*Feb 14,2012 3:45:03 PM yimao E-Porcelain GNU C++ Accepted 380ms 1800KB*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
#define maxn 100020

void up_max(int &x,int y){if((x<y)||(x==-1))x=y;}
void up_min(int &x,int y){if((x>y)||(x==-1))x=y;}

int dp[maxn];
int a[110];
int t[110]; // t[i]: consecutive length=i, the minmum value;

int solve(int n){
    int i,j,sum=0;
    for(i=1;i<=n;++i) sum+= a[i];
    t[n]= sum;
    t[0]= 0;
    for(i=1;i<=n;++i){
        int s=0;
        for(j=1;j<=i;++j)
            s+= a[j];
        t[i]=s;
        for(j=i+1;j<=n;++j){
            s-= a[j-i];
            s+= a[j];
            up_min( t[i], s );
        }
    }
    return sum;
}
int main()
{
    int n,m,i,j,k;
    while(cin>>n>>m){
        MM(dp,-1);
        dp[0]= 0; 
        for(i=1;i<=n;++i){
            int num;
            scanf("%d",&num);
            for(j=1;j<=num;++j)
                scanf("%d", a+j);
            int sum= solve(num);

            for(j=m;j>0;--j){
                for(k=1;k<=num&&k<=j;++k)
                    up_max( dp[j], dp[j-k]+ ( sum- t[num-k] ) );
            }
        }
        printf("%d\n", dp[m]);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值