剪气球串(状压dp或普通dp)

剪气球串(360公司2017春招真题)

http://exercise.acmcoder.com/online/online_judge_ques?ques_id=3862&konwledgeId=42

小明买了一些彩色的气球用绳子串在一条线上,想要装饰房间,每个气球都染上了一种颜色,每个气球的形状都是各不相同的。我们用1到9一共9个数字表示不同的颜色,如12345则表示一串5个颜色各不相同的气球串。但小明希望得到不出现重复颜色的气球串,那么现在小明需要将这个气球串剪成多个较短的气球串,小明一共有多少种剪法?如原气球串12345的一种是剪法是剪成12和345两个气球串。

注意每种剪法需满足最后的子串中气球颜色各不相同(如果满足该条件,允许不剪,即保留原串)。两种剪法不同当且仅当存在一个位置,在一种剪法里剪开了,而在另一种中没剪开。详见样例分析。

输入

第一行输入一个正整数n(1≤n≤100000),表示气球的数量。

第二行输入n个整数a1,a2,a3...an,ai表示该气球串上第i个气球的颜色。对于任意i,有1≤ai≤9。

样例输入

3

扫描二维码关注公众号,回复: 9941301 查看本文章

1 2 3

输出

输出一行,第一行输出一个整数,表示满足要求的剪法,输出最终结果除以1000000007后的余数。

样例输出

4

时间限制

C/C++语言:2000MS

其他语言:4000MS

内存限制

C/C++语言:131072KB

其他语言:655360KB

一直RE。好像是数组问题。但是不用状压我也不知道了。

RE代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod=1000000000+7;
int n;
int a[600];
int dp[100000+100][600];
int main()
{

   scanf("%d",&n);
        ///memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int big=(1<<n)-1;
        dp[1][(1<<a[1])-1]=1;///位置是1,当前状态是s的总方法
        for(int i=2;i<=n;i++){
            int k=(1<<(a[i]-1));
            for(int j=0;j<=512;j++){
                dp[i][k]+=dp[i-1][j];///没连
                dp[i][k]%=mod;
                if(!(k&j)){///如果其中没有相同颜色的话
                    dp[i][j|k]=dp[i-1][j];
                    dp[i][j|k]%=mod;
                }
            }
        }
        LL ans=0;
        for(int i=1;i<=512;i++){
            ans+=dp[n][i];
            ans%=mod;
        ///    cout<<"n:"<<n<<"  i:"<<i<<"  dp[][]"<<dp[n][i]<<endl;
        }

        printf("%lld\n",ans);

}

额。后来看了正解。

没想到啊。。。。

一维数组就可以解决。思路是这样的:

dp[i]表示到第i个位置的所有情况。

就i位置而言,有2种情况:

1.单独。

2.他可以和i-1位置连在一起,但是不和前边的某一个位置连在一起

AC代码:

#include <iostream>
#include <vector>
#include <iomanip>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <string>
using namespace std;
const int MOD = 1e9 + 7;
int main()
{
	int n=0,a[100000];
	while(cin>>n)
    {
		int dp[100001],num[10];
		for (int i=1;i<=n;i++){
			cin>>a[i];
		}
		for (int i=1;i<=n;i++){
			memset(num,0,sizeof(num));
			num[a[i]]++;
			dp[i]=dp[i-1];
			for (int j=i-1;j>=0;j--){
				num[a[j]]++;
				if (num[a[j]]>=1)///有重复的了。
					break;
				if (j==0)
					dp[i]++;
				else 		
				dp[i]=(dp[i]+dp[j-1])%MOD;
			}
		}
		cout<<dp[n]<<endl;
	}
    return 0;
}
发布了565 篇原创文章 · 获赞 110 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/xianpingping/article/details/88187809