剪气球串(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 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;
}