我不想写背景(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 2
3 2 5
4 1
1 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、
1≤S,Ai,Ci≤100、1≤Mi,Li,Di≤10000
分析
动归,对于每一个时刻的每一个能力值,有三种可能状态。 (详见代码)
代码
#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 10
3 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%的数据,
N≤10,1≤BMin≤BMax≤106
。
100%的数据,
N≤12,0≤ai≤4∗105,1≤BMin≤BMax≤1012。
分析
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;
}