dp

1.codeforce-----Bicolorings

 

 

题意:在 2xn 的表中只能放两个颜色,求可分成m个区域的个数

三维数组DP解决

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
using namespace std;

#define  inf 0x3f3f3f3f
const long long mod=998244353;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
long long  dp[1010][2010][5];

int main(int argc, char** argv) 
{   
   	int n,m;
   	cin>>n>>m;
   	memset(dp,0,sizeof(dp));
   	dp[1][2][0]=1;
	dp[1][3][1]=1;
	dp[1][3][2]=1;
	dp[1][2][3]=1;  
   	for(int i=1;i<=n;i++)
   	 for(int v=1;v<=m;v++)
		{
			int j=v+1;         //防止数组越界 
		for(int k=0;k<4;k++)
		{  
	     	
			if(k==0)
			{
				dp[i][j][k]+=dp[i-1][j][0]+dp[i-1][j][1]+dp[i-1][j][2]+dp[i-1][j-1][3];
				dp[i][j][k]%=mod;

			}       
			if(k==1)
			{
				dp[i][j][k]+=dp[i-1][j-1][0]+dp[i-1][j][1]+dp[i-1][j-2][2]+dp[i-1][j-1][3];
				dp[i][j][k]%=mod;
			}
			if(k==2)
			{
				dp[i][j][k]+=dp[i-1][j-1][0]+dp[i-1][j-2][1]+dp[i-1][j][2]+dp[i-1][j-1][3];
				dp[i][j][k]%=mod;
			}
			if(k==3)
			{
				dp[i][j][k]+=dp[i-1][j-1][0]+dp[i-1][j][1]+dp[i-1][j][2]+dp[i-1][j][3];
				dp[i][j][k]%=mod;
			}
		
		} 
		}
		cout <<(dp[n][m+1][0]+dp[n][m+1][1]+dp[n][m+1][2]+dp[n][m+1][3])%mod<<endl;
		 
	return 0;
}

2.

                                                问题 C: Evolution Game

                                                                 时间限制: 1 Sec  内存限制: 128 MB

题目描述

In the fantasy world of ICPC there are magical beasts. As they grow, these beasts can change form, and every time they do they become more powerful. A beast cannot change form completely arbitrarily though. In each form a beast has n eyes and k horns, and these affect the changes it can make.  
 
A beast can only change to a form with more horns than it currently has. 
A beast can only change to a form that has a difference of at most w eyes. So, if the beast currently has n eyes it can change to a form with eyes in range [n - w, n + w]. 
  
A beast has one form for every number of eyes between 1 and N, and these forms will also have an associated number of horns. A beast can be born in any form. The question is, how powerful can one of these beasts become? In other words, how many times can a beast change form before it runs out of possibilities? 

 

输入

The first line contains two integers, N and w, that indicate, respectively, the maximum eye number, and the maximum eye difference allowed in a change (1 ≤ N ≤ 5000; 0 ≤ w ≤ N).  
The next line contains N integers which represent the number of horns in each form. I.e. the ith number, h(i), is the number of horns the form with i eyes has (1 ≤ h(i) ≤ 1 000 000). 

 

输出

For each test case, display one line containing the maximum possible number of changes. 

 

样例输入

复制样例数据
5 5
5 3 2 1 4

样例输出

4

提示

Start with 1 horn and 4 eyes, and it can change 4 times: (1 horn 4 eyes) -> (2 horns 3 eyes) -> (3 horns 2 eyes) -> (4 horns 5 eyes) -> (5 horns 1 eye). 

题目大意:一头怪兽可以变换形态,最大变到N只眼,眼睛能变化的范围是W,即[N-w,N+w]。下面有N个数字,分别代表第i只眼睛的时候对应的角数,问最多可以变化多少个形态,怪物的初始状态随机,问最大的变化状态

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <stdlib.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <bitset>
#include <stack>
#include <queue>
#include <set>
#include <vector>
#include <map>

using namespace std;
const int INF = 0x3f3f3f3f;
struct node
{
    int eye;
    int horn;
    int res;
};
node arr[5000+50];
int n, w;

int  dp(int i)
{
    int& ans=arr[i].res;
    if(ans>0) return ans;
    ans=1;
    int e_max=arr[i].eye+w;
    int e_min=arr[i].eye-w;
    for(int j=1;j<=n;j++)
    {
        if(arr[j].horn>arr[i].horn&&arr[j].eye<=e_max&&arr[j].eye>=e_min)
              ans=max(ans,dp(j)+1);
    }
    return ans;

}
int main()
{
    while(cin >> n>> w)
    {
        memset(arr,0,sizeof(arr));
        for(int i=1; i<=n; i++)
        {
            cin>>arr[i].horn;
            arr[i].eye=i;
            arr[i].res=0;
        }
        for(int i=1;i<=n;i++)
        dp(i);
        int maxx=-1;
        for(int i=1;i<=n;i++)
        {
            if(arr[i].res>maxx)
                maxx=arr[i].res;
        }
        cout<<maxx-1<<endl;
    }
}

3                                                                    Winner Winner 

                                                        时间限制: 1 Sec  内存限制: 128 MB

题目描述

FZU Code Carnival是由福州大学ACM-ICPC培训中心主办的一项计划竞赛。该活动主要包括ACM-ICPC等编程竞赛,力争在未来为参与者提供有趣的代码挑战。
在比赛开始之前,YellowStar想知道哪些球队可能成为赢家。YellowStar计算了每个团队的技能,包括数据结构,动态规划,图论等。为了简化预测模型,YellowStar仅列出M技能,每个团队掌握的技能由长度为M的01序列表示。 1意味着团队已经掌握了这项技能,而0则没有。
如果一支球队比其他球队弱,那么这支球队就无法成为赢家。否则,YellowStar认为球队可能获胜。对于A组和B组的技能(a1,a2,...,aM)(b1,b2,...,bM),如果∀i∈[1,M],ai≤bi和∃i∈[1,M],ai <bi则A组弱于B组 。
由于YellowStar最近忙于为FZU Code Carnival做准备,他没有时间预测哪支球队将成为N队的冠军。所以他要求你写一个程序来计算可能成为赢家的球队数量。

输入:

标准输入以下列格式给出

M N                     

s1 s2 . . . sN   , si的二进制表示表示第i个队伍掌握的技能

1 ≤ N ≤ 2 × 106
1 ≤ M ≤ 20
0 ≤ si < 2M

打印一行表示答案。

#include <iostream>
#include <cstring>
#include <string>
#include <vector>

using namespace std;
const int maxn=1024*1024+10;
int arr[maxn];
int vis[maxn];

int m;

int main()
{
    int n;
    scanf("%d%d",&n,&m);
    int x;
    for(int i=0; i<n; i++)
    {
        scanf("%d",&x);
        arr[x]++;
    }
    int num=(1<<m)-1;
    int sum=0;
    for(int i=num;i>=0;i--)
    {
        if(!vis[i])
        sum+=arr[i];
        if(arr[i]!=0||vis[i])
        {
            for(int j=1;j<(1<<m);j<<=1)
            {
                if(i&j)
                vis[i^j]=1;
            }

        }
    }

    printf("%d\n",sum);

    return 0;
}

状压DP,从最大的长度,全部由的1的数开始往下分,每次列举少一个1的所有情况,用vis数组标记可以别其他状态覆盖的状态;

 

4                                                                                   Team

                                                           时间限制: 1 Sec  内存限制: 128 MB

ACM-ICPC是一款有趣的游戏。参加这场比赛的球队必须完全由(不多也不少)三人组成队。每年,许多新成员都将加入FZU ACM团队。如何组建团队成为一个大问题。
今年有3*N名成员。每个成员都有一个能力值Wi。如果三个不同的成员x,y,z组成一个团队,该团队的力量是Wx,Wy,Wz的最小值。
有M对关系,他们之间是好朋友。如果成员A和成员B是最好的朋友,他们必须在同一个团队中。我们希望组建N支球队,并获得这N支球队的最大总和。你能帮助我们吗?

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>

using namespace std;
const int maxn=3*1000+10;
typedef long long ll;

ll a[maxn];
ll b[maxn];
ll dp[maxn][maxn];
int fa[maxn];

int Find(int x)
{
    return fa[x]==-1?x:fa[x]=Find(fa[x]);
}
void Union(int x,int y)
{
   int t1=Find(x);
   int t2=Find(y);

   if(t1!=t2)
   {
       fa[t2]=t1;
       a[t1]=min(a[t1],a[t2]);
       b[t1]+=b[t2];
       b[t2]=0;
   }
}
int main()
{
    int n,m;
    memset(fa,-1,sizeof(fa));
    scanf("%d%d",&n,&m);
    int n2=n*3;
    for(int i=1;i<=n2;i++)
    {
        scanf("%lld",&a[i]);
        b[i]=1;
    }

    for(int i=0;i<m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        Union(x,y);
    }
    int ta=0;
    int tb=0;
    ll ans=0;

    for(int i=1;i<=n2;i++)
    {
        if(b[i]==1) a[ta++]=a[i];
        if(b[i]==2) b[tb++]=a[i];
        if(b[i]==3) ans+=a[i];
        if(b[i]>=4)
        {
            printf("-1\n");
            return 0;
        }
    }

    sort(a,a+ta);
    sort(b,b+tb);

    memset(dp,-1,sizeof(dp));
    dp[0][0]=0;
    for(int i=0;i<=ta;i++)
      for(int j=0;j<=tb;j++)
    {
       if(dp[i][j]!=-1)
       {
           dp[i+3][j]=max(dp[i+3][j],dp[i][j]+a[i]);
           dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]+min(a[i],b[j]));
       }
    }
    //dp[i][j] i表示一个人一组的选了i个,两个人一组的选了j个; 原来的状态决定之后的状态
    if(dp[ta][tb]==-1)
        printf("-1\n");
    else
        printf("%lld\n",ans+dp[ta][tb]);

    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值