https://cn.vjudge.net/contest/228358#problem/K
四个汉诺塔移动问题,之前是三个用2^n-1就行,这个题就是找规律,先暴力做上100个数据,然后找到之间的关系,用Java大数写
代码:
import java.util.*;
import java.io.*;
import java.math.*;
public class Main{
public static void main(String[] args) {
BigInteger maxn,tt,ttt,h,ant;
int j,i,ans = 0;
BigInteger a[]=new BigInteger[10005];
a[0]=BigInteger.valueOf(0);
a[1]=BigInteger.valueOf(1);
ans=2;
ant=BigInteger.valueOf(2);
for(i=2,j=1;i<10001;i++,j++)
{
if(j>ans) {
ans++;
ant=ant.multiply(BigInteger.valueOf(2));
j=1;
}
a[i]=a[i-1].add(ant);
}
Scanner c=new Scanner(System.in);
while(c.hasNext())
{
System.out.println(a[c.nextInt()]);
}
return;
}
}
https://cn.vjudge.net/contest/228358#problem/T
截木棍,每次截木棍之前的花费是,要截断的木棍的长度,求使木棍成为数组对应的截断点,最小花费是???
区间dp
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#include <sstream>
#define inf 0x7fffffff
#define ll long long
#define mod 1000000007
using namespace std;
int dp[100][100],a[100];
int main()
{
int n,l,i,j,k,p,maxn,tt;
while(~scanf("%d",&l)&&l)
{
scanf("%d",&n);
a[1]=0;
int m;
m=n+1;
for(i=2;i<=m;i++)
scanf("%d",&a[i]);
a[m+1]=l;
for(i=1;i<=m;i++)
dp[i][i+1]=0;
for(k=2;k<=m;k++)
{
for(i=1;i<=m-k+1;i++)
{
p=i+k;
maxn=inf;
for(j=i+1;j<p;j++)
{
tt=dp[i][j]+dp[j][p]+a[p]-a[i];
maxn=min(maxn,tt);
}
dp[i][p]=maxn;
}
}
printf("The minimum cutting is %d.\n",dp[1][m+1]);
}
}
https://cn.vjudge.net/contest/228358#problem/E
求一个字符串至少分成几段才可以使每段都是回文串,也是区间dp,比较裸
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#include <sstream>
#define inf 0x7fffffff
#define ll long long
#define mod 1000000007
using namespace std;
int dp[1005];
char s[1005];
bool ok(int x,int y)
{
int p,q;
for(p=x,q=y;p<=q;p++,q--)
{
if(s[p]!=s[q])return false;
}
return true;
}
int main()
{
int n,i,j,t,k,p,maxn,q,tt;
scanf("%d",&t);
while(t--)
{
//string s;
//cin>>s+1;
scanf("%s",s+1);
memset(dp,0,sizeof(dp));
n=strlen(s+1);
dp[0]=0;
for(k=1;k<=n;k++)
{
dp[k]=k;
for(i=0;i<k;i++)
{
if(ok(i+1,k))
dp[k]=min(dp[k],dp[i]+1);
}
}
printf("%d\n",dp[n]);
}
}
https://cn.vjudge.net/contest/228358#problem/B
A和B轮流最优的选择从左到右的某一段或者从右到左的某一段,选择后删去。。求这种情况下他们的差
分析:
区间dp,dp[i][j]就是A从选择i到j的某一段的最后的差,重要的转移方程是dp[i][j]=max(dp[i][j],sum[p]-sum[i-1]-dp[p+1][j])和dp[i][j]=max(dp[i][j],sum[j]-sum[p-1]-dp[i][p-1])
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#include <sstream>
#define inf 0x7fffffff
#define ll long long
#define mod 1000000007
using namespace std;
int dp[200][200],a[200],sum[200];
int main()
{
int n,i,j,k,maxn,tt,p;
while(~scanf("%d",&n)&&n)
{
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
scanf("%d",&dp[i][i]);
sum[0]=0;
for(i=1;i<=n;i++)
{
sum[i]=sum[i-1]+dp[i][i];
}
for(k=1;k<n;k++)
{
for(i=1;i<=n-k;i++)
{
j=i+k;
maxn=-inf;
for(p=i;p<=j;p++)
{
tt=sum[p]-sum[i-1]-dp[p+1][j];
maxn=max(maxn,tt);
}
for(p=j;p>=i;p--)
{
tt=sum[j]-sum[p-1]-dp[i][p-1];
maxn=max(maxn,tt);
}
dp[i][j]=maxn;
}
}
printf("%d\n",dp[1][n]);
}
}
/*
4
4 -10 -20 7
4
1 2 3 4
*/
感觉这个题是目前做的比较难理解的题,当时做的时候题意都不大懂,看了好久才懂。。。
https://cn.vjudge.net/contest/228358#problem/A
这个题看着很难,很难处理公共,但是加一个数组就行了,用来处理在原数组中的位置,然后求最长上升子序列
鬼知道我为什么一直wrong,最后发现竟然是数组开小了,数组开小竟然有这种操作,,,,气人
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#include <sstream>
#define inf 8000000000
#define ll __int64
#define mod 1000000007
using namespace std;
int vis[100005];
int a[300000],b[300000];
int main()
{
int t,i,j,n,p,q,num,ans,maxn,len,k;
scanf("%d",&t);
k=1;
while(t--)
{
printf("Case %d: ",k);
k++;
scanf("%d%d%d",&n,&p,&q);
memset(vis,0,sizeof(vis));
p++;
q++;
for(i=1;i<=p;i++){
scanf("%d",&num);
vis[num]=i;
}
//maxn=0;
ans=0;
//len=0;
for(i=1;i<=q;i++)
{
scanf("%d",&num);
if(vis[num])
{
a[ans++]=vis[num];
}
}
if(ans==0)
{
printf("0\n");
continue;
}
len=1;
//dp[1]=a[0];
b[1]=a[0];
maxn=1;
for(i=1;i<ans;i++)
{
int u;
//u=upper_bound(b+1,b+len+1,a[i])-b;
if(a[i]>=b[len])
{
b[++len]=a[i];
maxn=len;
}
else{
u=upper_bound(b+1,b+len+1,a[i])-b;
b[u]=a[i];
}
}
printf("%d\n",maxn);
}
}
其他的就是之前做过的,,,