动态规划弱渣决定开始补脑
ZOJ2402 类似于最长递增子序列
f(n, m) = f(n-1, m/2) + f(n-1, (m-1)/2) +...... + f(n-1, 1)
f[1][i]=i
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
//f(n, m) = f(n-1, m/2) + f(n-1, (m-1)/2) +...... + f(n-1, 1)
//f[1][i]=i
long long f[11][2001];
int main()
{
int n,m,i,j,k;
int t;
memset(f,0,sizeof(f));
for(i=1;i<2001;i++)f[1][i]=i;
for(i=2;i<11;i++)
{
for(j=2;j<2001;j++)
{
for(k=j;k>1;k--)
{
f[i][j]+=f[i-1][k/2];
}
}
}
cin>>t;
int ca=1;
while(t--)
{
cin>>n>>m;
printf("Case %d: n = %d, m = %d, # lists = %lld\n",ca++,n,m,f[n][m]);
}
return 0;
}
ZOJ2401简单的dp
注意边界
dp[i][j]表示a的前i个与b的前j个是否能构成c的前i+j个
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 220
int main()
{
bool dp[N][N];
char a[N],b[N],c[2*N];
int t,i,j;
int k=1;
cin>>t;
while(t--)
{
scanf("%s%s%s",a,b,c);
int lena=strlen(a);
int lenb=strlen(b);
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(i=0;i<=lena;i++)//注意边界当a用完时dp[i][j] i=lena
{
for(j=0;j<=lenb;j++)
{
if(dp[i][j])
{
if(a[i]==c[i+j])dp[i+1][j]=1;
if(b[j]==c[i+j])dp[i][j+1]=1;
}
}
}
printf("Data set %d: ",k++);
if(dp[lena][lenb])printf("yes\n");
else printf("no\n");
}
return 0;
}
CF267
The new ITone 6 has been released recently and George got really keen to buy it. Unfortunately, he didn't have enough money, so George was going to work as a programmer. Now he faced the following problem at the work.
Given a sequence of n integers p1, p2, ..., pn. You are to choose k pairs of integers:
in such a way that the value of sum is maximal possible. Help George to cope with the task.
The first line contains three integers n, m and k (1 ≤ (m × k) ≤ n ≤ 5000). The second line contains n integers p1, p2, ..., pn (0 ≤ pi ≤ 109).
Print an integer in a single line — the maximum possible value of sum.
5 2 1 1 2 3 4 5
9
7 1 3 2 10 7 18 5 33 0
61
dp[i][j] 表示在前j个选i对的最大值
s[i] 是前缀和
dp[i][j]=max(dp[i][j-1],dp[i-1][j-m]+s[j]-s[j-m]);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 5005
__int64 dp[N][N];
__int64 a[N],s[N];
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
for(int i=1;i<=n;i++)scanf("%d",&s[i]),s[i]+=s[i-1];
for(int i=1;i<=k;i++)
{
for(int j=i*m;j<=n;j++)
{
dp[i][j]=max(dp[i][j-1],dp[i-1][j-m]+s[j]-s[j-m]);
//printf("i= %d j=%d ,%d\n",i,j,dp[i][j]);
}
}
printf("%I64d\n",dp[k][n]);
}
return 0;
}
/*
7 2 3
2 10 7 18 5 33 6
*/
1007. Maximum Subsequence Sum (25)
Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to be { Ni, Ni+1, ..., Nj } where 1 <= i <= j <= K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.
Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.
Input Specification:
Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (<= 10000). The second line contains K numbers, separated by a space.
Output Specification:
For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.
Sample Input:10 -10 1 2 3 4 -5 -23 3 7 -21Sample Output:
10 1 4
#include<iostream>
#include<cstdio>
using namespace std;
int dp[10010];
int main()
{
int T,n,i,t,a[10010],st,stop,max,j;
while(~scanf("%d",&n)){
scanf("%d",&a[1]);
dp[1]=a[1];
stop=1;j=1;
st=1;
max=dp[1];
for(i=2;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]>dp[i-1]+a[i]){
dp[i]=a[i];
st=i;
}
else dp[i]=dp[i-1]+a[i];
if(max<dp[i]){
max=dp[i];
stop=st;
j=i;
}
}
// printf("Case %d:\n",t);
if(max<0)printf("0 %d %d\n",a[1],a[n]);
else printf("%d %d %d\n",max,a[stop],a[j]);
if(T>0)printf("\n");
}
return 0;
}//test: 3 1 -9 3 -1 10 -2 3 -2 10 -1
1033. To Fill or Not to Fill (25)
With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.
Input Specification:
Each input file contains one test case. For each case, the first line contains 4 positive numbers: Cmax (<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; Davg (<=20), the average distance per unit gas that the car can run; and N (<= 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: Pi, the unit gas price, and Di (<=D), the distance between this station and Hangzhou, for i=1,...N. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print "The maximum travel distance = X" where X is the maximum possible distance the car can run, accurate up to 2 decimal places.
Sample Input 1:50 1300 12 8 6.00 1250 7.00 600 7.00 150 7.10 0 7.20 200 7.50 400 7.30 1000 6.85 300Sample Output 1:
749.17Sample Input 2:
50 1300 12 2 7.10 0 7.00 600Sample Output 2:
The maximum travel distance = 1200.00
后来才想到经过加油站油量是可以有剩余的,只要使每段路的油费尽量小就可以了,贪心解决
dp代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<map>
#define N 550
#define INF 0x7fffffff
using namespace std;
int num;
double destination,capacity,disavg;
double dp[N];
struct ss
{
double price;
double dis;
}a[N];
double dis[N];
bool cmp(ss a,ss b)
{
return a.dis<b.dis;
}
int main()
{
while(~scanf("%lf%lf%lf%d",&capacity,&destination,&disavg,&num))
{
int i,j;
for(i=0;i<num;i++)
{
scanf("%lf%lf",&a[i].price,&a[i].dis);
}
a[num].dis=destination;
a[num].price=1000000000000;
sort(a,a+num+1,cmp);
for(i=0;i<=num;i++)dis[i]=a[i].dis;
for(i=0;i<=num;i++)dp[i]=INF;
for(i=0;i<=num;i++)
{
// printf("-- %d %lf %lf\n",i,a[i].dis,a[i].price);
}
if(abs(a[0].dis)>0.0000001){
printf("The maximum travel distance = 0.00\n");
continue;
}
double MAX_dis=capacity*disavg;
dp[0]=0;
for(i=1;i<=num;i++)
{
if(a[i].dis-a[i-1].dis>MAX_dis)break;
j=lower_bound(dis,dis+num,a[i].dis-MAX_dis)-dis;
// printf("-- %d %d \n",i,j);
for(;j<i;j++)
{
dp[i]=min(dp[i],dp[j]+(a[i].dis-a[j].dis)*a[j].price/disavg);
// printf("%d %lf\n",j,dp[i]);
}
}
if(i<=num)
printf("The maximum travel distance = %.2lf\n",a[i-1].dis+MAX_dis);
else printf("%.2lf\n",dp[num]);
}
return 0;
}
/*
50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300
*/
贪心代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<map>
#define N 550
#define INF 0x7fffffff
using namespace std;
int n;
double destination,capacity,disavg;
double node[N*2];
double MAX_dis;
struct ss
{
double price;
double dis;
}a[N];
bool cmp(ss a,ss b)
{
return a.dis<b.dis;
}
struct sss
{
double a,b,cost;
}point[N*2];
int main()
{
while(~scanf("%lf%lf%lf%d",&capacity,&destination,&disavg,&n))
{
MAX_dis=capacity*disavg;
int i,j,k=0;
for(i=0;i<n;i++)
{
scanf("%lf%lf",&a[i].price,&a[i].dis);
if(a[i].dis<destination)node[k++]=a[i].dis;
if(a[i].dis+MAX_dis<destination)node[k++]=a[i].dis+MAX_dis;
}
a[n].dis=destination;
sort(a,a+n+1,cmp);
if(abs(a[0].dis)>0.0000001){
printf("The maximum travel distance = 0.00\n");
continue;
}
for(i=1;i<=n;i++){
if(a[i].dis-a[i-1].dis>MAX_dis)break;
}
if(i<=n){
printf("The maximum travel distance = %.2lf\n",a[i-1].dis+MAX_dis);
continue;
}
node[k++]=destination;
sort(node,node+k);
int kk=0;
for(i=1;i<k;i++)
{
if(node[i]!=node[i-1])
{
point[kk].a=node[i-1];
point[kk].b=node[i];
point[kk++].cost=INF;
}
}
for(i=0;i<kk;i++)
{
// printf("// %lf %lf %lf\n",point[i].a,point[i].b,point[i].cost);
}
for(i=0;i<n;i++)
{
for(j=0;j<kk;j++)
{
if(point[j].a>=a[i].dis&&point[j].b<=a[i].dis+MAX_dis)
{
if(a[i].price<point[j].cost)point[j].cost=a[i].price;
}
}
}
for(i=0;i<kk;i++)
{
// printf("//** %lf %lf %lf\n",point[i].a,point[i].b,point[i].cost);
}
double ans=0;
for(i=0;i<kk;i++)
{
ans+=(point[i].b-point[i].a)/disavg*point[i].cost;
}
printf("%.2lf\n",ans);
}
return 0;
}
ZOJ3725 DP解排列计数
题目链接:Click here~~
题意:
n个格子排成一条直线,可以选择涂成红色或蓝色,问最少 m 个连续为红色的方案数。
解题思路:
应该是这次 ZOJ 月赛最水的一题,可惜还是没想到。。。
dp[i] 表示前 i 个最少 m 个连续为红色的方案数。
转移时,分类讨论:
1、前 i-1 个已经满足这个性质,那么,第 i 个随意涂色,方案数为 dp[i-1] * 2 。
2、前 i-1 个不满足这个性质,那么,要想成为方案,区间 [i-m+1,i] 必须涂成红色。并且,下标为 i-m 这个点必须是蓝色,否则就与 情况1 重复了。
而且正是由于这一点,只要剩下的区间 [1,i-m-1] 不满足这个性质,就能保证整个区间 [1,i-1] 不满足这个性质。方案数为 2^(i-m-1) - dp[i-m-1]。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int N=1e5+5;
const int mod=1e9+7;
int dp[N],pow[N]={1};
int main()
{
int n,m,i;
for(i=1;i<N;i++)pow[i]=pow[i-1]*2%mod;
while(~scanf("%d%d",&n,&m))
{
memset(dp,0,sizeof(dp));
dp[m]=1;
for(i=m+1;i<=n;i++)dp[i]=(dp[i-1]*2%mod+(pow[i-m-1]-dp[i-m-1]+mod)%mod)%mod;
printf("%d\n",dp[n]);
}
return 0;
}