Contents:
(exer.c/.cpp/.pas)
奶牛Bessie有N分钟时间跑步,每分钟她可以跑步或者休息。若她在第i分钟跑步,可以跑出D_i米,同时疲倦程度增加1(初始为0)。若她在第i分钟休息,则疲倦程度减少1。无论何时,疲倦程度都不能超过M。另外,一旦她开始休息,只有当疲惫程度减为0时才能重新开始跑步。在第N分钟后,她的疲倦程度必须为0。
输入文件名为(exer.in)。
第一行,两个整数,代表N和M。 接下来N行,每行一个整数,代表D_i。
输出文件名为(exer.out)。
Bessie想知道,她最多能跑的距离。
5 2
5 3 4 2 10
9
N < = 2000 , M < = 500 , D_i < = 1000
看到有两种状态,一开始想用f[i][1/0]表示第i分钟跑步或休息的最大价值,但是转移的时候因为不知道是从何时开始跑步或休息,所以很难列方程。所以可以用f[i][j][1/0]表示第i分钟跑步或休息,并能记录疲倦值的最值。
但是大可不必这么麻烦:
状态:f[i][j]表示前i分钟,疲倦值为j时的最远距离。
输出:f[n][0]
转移:f[i][j]=max(f[i][j],f[i-1][j-1]+a[i]) —>跑步
f[i][0]=f[i-1][0]
f[i][0]=max(f[i][0],f[i-j][j])—>休息的两种状态
TIPS:
Code:
#include
#include
#define MAXN 2500
int n,m;
int a[MAXN],f[MAXN][600];
int min(int a,int b){return aint max(int a,int b){return a>b?a:b;}
int main()
{
freopen("exer.in","r",stdin);
freopen("exer.out","w",stdout);
memset(f,-1,sizeof(f));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
f[0][0]=0;
for(int i=1;i<=n;i++)
{
f[i][0]=f[i-1][0];
for(int j=1;j<=min(i,m);j++)
{
f[i][0]=max(f[i][0],f[i-j][j]);
}
for(int j=1;j<=m;j++)
{
f[i][j]=max(f[i][j],f[i-1][j-1]+a[i]);
}
}
printf("%d\n",f[n][0]);
return 0;
(cat.c/.cpp/.pas)
3 10 2
3 1 4 10
6 3 5 9 7 8 9
5 4 5 3 6 9
8
状态:f[i]表示高度为i时吃到最多的柿子
输出:f[1]
转移:g[j]=max(g[j],tmp)+hash[j][i];
f[i]=max(f[i],g[j]);
TIPS:
#include
#include
#define MAXN 2500
int n,h,d;
int f[MAXN],g[MAXN],a[MAXN],hash[MAXN][MAXN];
int max(int a,int b){return a>b?a:b;}
int main()
{
freopen("cat.in","r",stdin);
freopen("cat.out","w",stdout);
scanf("%d%d%d",&n,&h,&d);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
for(int j=1;j<=a[i];j++)
{
int p;
scanf("%d",&p);
hash[i][p]++;
}
}
for(int i=h;i>=1;i--)
{
int tmp=0;
if(i+d<=h)
{
tmp=f[i+d];
}
for(int j=1;j<=n;j++)
{
g[j]=max(g[j],tmp)+hash[j][i];
f[i]=max(f[i],g[j]);
}
}
printf("%d\n",f[1]);
return 0;
}
(seq.c/.cpp/.pas)
将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个“<”。答案对2012取模。
输入文件名为(seq.in)。
第一行2个整数n,k。
输出文件名为(seq.out)。
一个整数表示答案。
5 2
66
对于30%的数据:n <= 10
对于100%的数据:k < n <= 1000
对于前30%的数据可以打表找规律
Code:
#include
#include
#include
#define MAXN 1000
using namespace std;
int n,k,ans;
int a[MAXN];
int count(int a[])
{
int cnt=0;
for(int i=2;i<=n;i++)
{
if(a[i]>a[i-1])
{
cnt++;
}
}
return cnt;
}
int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
a[i]=i;
}
do
{
if(count(a)==k)
{
ans++;
ans%=2012;
}
}while(next_permutation(a+1,a+1+n));
printf("%d\n",ans%2012);
return 0;
}
具体分析就显然了,先一行一行来分析
f[n][1]=f[n-1][1]*2+(n-1):
现在我们就希望知道k=1的情况了,能否知道当k>=2的情况,但是事实是并非那么简单。
把所有情况列出来
所以你看到了,我就是枚举找规律做的..
当然这道题正解是考虑不同的位置,不同的情况具体分析。式子是一样的.
Code:
#include
#include
#define MOD 2012
int n,k;
int f[1200][1200];
void pre_()
{
f[0][0]=1;
f[1][0]=1;
}
int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
pre_();
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
f[i][0]=1;
for(int j=1;j<=k;j++)
{
f[i][j]=((f[i-1][j]*(j+1))%MOD+((i-j)*f[i-1][j-1])%MOD)%MOD;
f[i][i-1]=1;
}
}
printf("%d\n",f[n][k]%MOD);
return 0;
}
(clean.c/.cpp/.pas)
Candy家里总共有n个垃圾等待处理,每个垃圾对于Candy和飘飘乎居士处理的时间都是不同的,而且每个垃圾只需要一个人处理。当然,Candy和飘飘乎居士可以同时处理不同的垃圾。记两人中耗费最长时间为最后总时间。Candy希望能够尽快的处理完所有的垃圾,因此,他想要知道处理完这些垃圾最少需要耗费多少时间?
输入文件名为(clean.in)。
第一行一个正整数n,表示一共有n个垃圾需要处理
接下来一个2*n的矩阵。
矩阵第一行第i个数表示candy处理第i个垃圾所需消耗的时间
矩阵第二行第i个数表示飘飘乎居士处理第i个垃圾所需消耗的时间
输出文件名为(clean.out)。
一行,最后耗费的时间
5
2 4 1 4 5
2 1 3 4 1
5
Candy完成垃圾3与垃圾4的清理,耗时为5
飘飘乎居士完成垃圾1 2 5的清理,耗时为4,由于Candy耗费的时间较长,所以记Candy耗费时间为最后总时间,所以最后答案为5。
·对于30%的数据
0 < n<=30
对于100%的数据 0< n<=1000,Candy和飘飘乎居士处理每个垃圾的时间<=10,对任何一个人处理所有垃圾时间总和<=4000
不会啊,怎么办?
暴力30分,贪心70分,加在一起就A了~并且分数无交集。
Code:
#include
#include
#include
#define MAXN 1500
using namespace std;
int n,k;
int sum_a,sum_b,ans=0x3f3f3f3f;
int a[MAXN],b[MAXN],tmp[MAXN];
int cmp(int a,int b){return a>b?1:0;}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return avoid dfs(int deep,int cnt1,int cnt2)
{
if(cnt1>ans||cnt2>ans)
return ;
if(deep>n)
{
ans=min(ans,max(cnt1,cnt2));
return ;
}
dfs(deep+1,cnt1+a[deep],cnt2);
dfs(deep+1,cnt1,cnt2+b[deep]);
}
int main()
{
freopen("clean.in","r",stdin);
freopen("clean.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
}
if(n<=30)
{
dfs(1,0,0);
printf("%d\n",ans);
return 0;
}
for(int i=1;i<=n;i++)
{
if(a[i]>b[i])
{
sum_b+=b[i];
}
if(a[i]if(a[i]==b[i])
{
tmp[++k]=a[i];
}
}
sort(tmp+1,tmp+1+k,cmp);
for(int i=1;i<=k;i++)
{
if(sum_a<=sum_b)
{
sum_a+=tmp[i];
continue;
}
if(sum_a>sum_b)
{
sum_b+=tmp[i];
continue;
}
}
printf("%d\n",max(sum_a,sum_b));
return 0;
}
正解:
用f[i,j]表示:完成前i项任务,若Candy花了j分钟,
那么飘飘乎居士最少花f[i,j]分钟。
a[i]表示:Candy完成第i项任务所花的时间;b[i]表示:飘飘乎居士完成第i项任务所花的时间。
则方程为:f[i,j]=Min{f[i-1,j]+b[i],f[i-1,j-a[i]]} 。当j
#include
#include
#define MAXN 1000
int n,sum,ans=0x3f3f3f;
int a[MAXN],b[MAXN],f[MAXN][MAXN<<2];
int min(int a,int b){return aint max(int a,int b){return a>b?a:b;}
int main()
{
freopen("clean.in","r",stdin);
freopen("clean.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
}
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=sum;j++)
{
if(j1][j]+b[i];
}
else f[i][j]=min(f[i-1][j]+b[i],f[i-1][j-a[i]]);
}
}
for(int j=0;j<=sum;j++)
{
ans=min(ans,max(j,f[n][j]));
}
printf("%d\n",ans);
return 0;
}