训练日记

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);
    }
}
其他的就是之前做过的,,,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值