【DP】TEST20170430

来源:互联网 发布:tt软件下载 编辑:程序博客网 时间:2024/05/18 04:05

我不想写背景(wtf.pas/c/cpp)

问题描述

    某巨魔去滑雪(没滑雪板),但他的技术并不精湛,在滑雪场里,每天会提供S门滑雪课。第i节课始于时间M i ,上课的时长为L i (只有在M i 时刻才能选择去上第i节课,其他时间不能选择上第i节课)。上完第i节课后,巨魔的滑雪能力会变成A i . (注意:这个能力是绝对的,不是能力的增长值)。 巨魔买了一张地图,地图上显示了N个可供滑雪的斜坡,从第i个斜坡的顶端滑至底部所需的时长D i ,以及每个斜坡所需要的滑雪能力C i ,以保证滑雪的安全性。巨魔的能力必须大于等于这个等级,以使得他能够安全滑下。 巨魔可以用他的时间来滑雪,上课,或者在旁边菊花丛中练习箭法,但是他必须在T时刻离开滑雪场。这意味着他必须在T时刻之前(或者T时刻)完成最后一次滑雪(或者上课)。 求巨魔在时间内最多可以完成多少次滑雪。这一天开始的时候,他的滑雪能力为1。

输入

    第一行3个数字,T、S、N。
    接下来S行,每行3个数字M i 、L i 、A i 。
    接下来N行,每行2个数字C i 、D i 。

输出

    一个整数,表示巨魔滑雪的最大次数。

输入样例

10 1 23 2 54 11 3

输出样例

6

样例解释

    0时刻,选择在第1个斜坡上滑雪,时间花费3。
    3时刻,选择上第1节课。滑雪技术提高到5,时间花费2。
    5时刻,选择在第2个斜坡上滑雪,时间花费1。
    6时刻,选择在第2个斜坡上滑雪,时间花费1。
    7时刻,选择在第2个斜坡上滑雪,时间花费1。
    8时刻,选择在第2个斜坡上滑雪,时间花费1。
    9时刻,选择在第2个斜坡上滑雪,时间花费1。
    10时刻,收队了。
    总滑雪次数:6

数据范围

50%的数据:1≤N,T≤1000。
100%的数据:1≤N,T≤10000、1S,Ai,Ci1001Mi,Li,Di10000

分析

    动归,对于每一个时刻的每一个能力值,有三种可能状态。 (详见代码)

代码

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int sm = 10000+10,ss = 100+10;int s,m,l,a,n,d,c,t,ans;int g[sm],cl[sm][ss],f[sm][ss],tm[ss];//g[i]时刻i的最大滑雪次数 //cl[i][j] i时刻结束能力值为j的课程的最晚开始时间//f[i][j] i时刻能力值为j的最大滑雪次数//tm[i] 能力值<=i的滑雪最短时间int main() {    freopen("wtf.in","r",stdin);    freopen("wtf.out","w",stdout);    memset(tm,0x3f,sizeof(tm));    memset(f,128,sizeof(f));//    scanf("%d%d%d",&t,&s,&n);    for(int i=1;i<=s;++i) {        scanf("%d%d%d",&m,&l,&a);        cl[m+l-1][a]=max(cl[m+l-1][a],m);    }    for(int i=1;i<=n;++i) {        scanf("%d%d",&c,&d);        for(int j=c;j<=100;++j)            tm[j]=min(tm[j],d);    }    f[0][1]=0;    for(int i=1;i<=t;++i)        for(int j=1;j<=100;++j) {            f[i][j]=f[i-1][j];            if(cl[i-1][j])f[i][j]=max(f[i][j],g[cl[i-1][j]]);            if(i-tm[j]>=0)f[i][j]=max(f[i][j],f[i-tm[j]][j]+1);            g[i]=max(g[i],f[i][j]);            ans=max(g[i],ans);        }    printf("%d\n",ans);    return 0;}

我真不想写背景(wth.pas/c/cpp)

问题描述

    某巨魔突然对等式很感兴趣,他正在研究 a 1 x 1 +a 2 x 2 +…+a n x n =B 存在非负整数解的条件,他要求你编写一个程序,给定 N、{a n }、以及 B 的取值范围,求出有多少 B 可以使等式存在非负整数解。

输入

    输入的第一行包含 3 个正整数,分别表示 N、BMin、BMax 分别表示数列的长度、B 的下界、B 的上界。
    输入的第二行包含 N 个整数,即数列{a n }的值。

输出

    输出一个整数,表示有多少 B 可以使等式存在非负整数解。

输入样例

2 5 103 5

输出样例

5

样例解释

对于 B=5,式子有 x1=0,x2=1。对于 B=6,式子有 x1=2,x2=0。对于 B=7,无解。对于 B=8,式子有 x1=1,x2=1。对于 B=9,式子有 x1=3,x2=0。对于 B=10,式子有 x1=0,x2=2。

数据范围

20%的数据,N≤5,1≤BMin≤BMax≤10。
40%的数据,N10,1BMinBMax106
100%的数据,N12,0ai4105,1BMinBMax1012

分析

    SPFA,理解g[i]为模minn余i的最小值

代码

#include<cstdio>#include<queue>#include<climits>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const ll inf = LLONG_MAX; const int sm = 5e5+10;int n,nxt,minn,a[15],ex[sm];ll t,bmax,bmin,dis[sm];queue<int>q;ll query(ll x) {    ll ans=0;    for(int i=0;i<minn;++i) {        if(dis[i]<=x) ans+=(x-dis[i])/minn+1;//minn是物品中权重最小的,故用它凑凑出的数最多    }    return ans;}int main() {    freopen("wth.in","r",stdin);    freopen("wth.out","w",stdout);    minn=INT_MAX;    scanf("%d%lld%lld",&n,&bmin,&bmax);    for(int i=1;i<=n;++i)        scanf("%d",&a[i]),minn=min(minn,a[i]);    for(int i=1;i<minn;++i)dis[i]=inf;    q.push(0);    while(!q.empty()) {        t=q.front();        q.pop();        for(int i=1;i<=n;++i) {            nxt = (t+a[i])%minn;            if(dis[nxt]>dis[t]+a[i]) {                dis[nxt]=dis[t]+a[i];                if(!ex[nxt]) {                    ex[nxt]=1;                    q.push(nxt);                }            }        }    }    printf("%lld\n",query(bmax)-query(bmin-1));    return 0;}