http://codeforces.com/contest/1185/problem/G1
题
意
:
n
首
音
乐
,
每
首
有
v
a
l
[
i
]
表
示
长
度
,
g
[
i
]
表
示
种
类
。
要
求
在
刚
好
满
足
时
间
T
的
情
况
下
,
听
歌
顺
序
的
方
案
数
,
(
相
邻
两
首
歌
种
类
不
能
相
同
题意:n首音乐,每首有 val[i]表示长度,g[i]表示种类。要求在刚好满足时间T的情况下,听歌顺序的方案数,(相邻两首歌种类不能相同
题意:n首音乐,每首有val[i]表示长度,g[i]表示种类。要求在刚好满足时间T的情况下,听歌顺序的方案数,(相邻两首歌种类不能相同
题
解
:
状
压
d
p
题解:状压dp
题解:状压dp
d
p
[
s
]
[
j
]
[
k
]
表
示
当
前
状
态
为
s
,
已
经
听
歌
的
时
间
为
j
,
最
后
一
首
歌
种
类
的
k
的
方
案
数
dp[s][j][k]表示当前状态为s,已经听歌的时间为j,最后一首歌种类的k的方案数
dp[s][j][k]表示当前状态为s,已经听歌的时间为j,最后一首歌种类的k的方案数
那
么
方
程
就
是
d
p
[
s
]
[
j
]
[
k
]
+
=
d
p
[
s
∣
(
1
<
<
i
)
]
[
j
−
v
a
l
[
i
]
]
[
g
[
i
]
]
那么方程就是 dp[s][j][k]+=dp[s|(1<<i)][j-val[i]][g[i]]
那么方程就是dp[s][j][k]+=dp[s∣(1<<i)][j−val[i]][g[i]]
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x) x&-x;
#define debugint(name,x) printf("%s: %d\n",name,x);
#define debugstring(name,x) printf("%s: %s\n",name,x);
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 1e5+5;
const int mod = 1e9+7;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll dp[1<<15][230][4];
int n,T,val[20],g[20];
ll solve(int s, int tmp, int k){
if(tmp == 0) return 1;
if(tmp < 0) return 0;
if(dp[s][tmp][k] != -1) return dp[s][tmp][k];
ll ans = 0;
for(int i = 0; i < n; i++){
if(!(s&(1<<i))){
if(g[i]!=k){
ans = (ans + solve(s^(1<<i),tmp-val[i],g[i]))%mod;
}
}
}
return dp[s][tmp][k] = ans;
}
int main() {
scanf("%d%d",&n,&T);
for(int i = 0; i < n; i++)
scanf("%d%d",&val[i],&g[i]);
mem(dp,-1);
int st = 1<<n;
printf("%lld\n",solve(0,T,0));
}
AC后发现内存快爆了,想办法优化一下:
可以发现dp的第二维实际上可以用一个变量进行记录
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<vector>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mem(a,b) memset(a,b,sizeof(a));
#define lowbit(x) x&-x;
#define debugint(name,x) printf("%s: %d\n",name,x);
#define debugstring(name,x) printf("%s: %s\n",name,x);
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 1e5+5;
const int mod = 1e9+7;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll dp[1<<15][4];
int n,T,val[20],g[20];
ll solve(int s, int tmp, int k){
if(tmp == T) return 1;
if(tmp > T) return 0;
if(dp[s][k] != -1) return dp[s][k];
ll ans = 0;
for(int i = 0; i < n; i++){
if(!(s&(1<<i))){
if(g[i]!=k){
// tmp += val[i];
ans = (ans + solve(s^(1<<i),tmp+val[i],g[i]))%mod;
}
}
}
return dp[s][k] = ans;
}
int main() {
scanf("%d%d",&n,&T);
for(int i = 0; i < n; i++)
scanf("%d%d",&val[i],&g[i]);
mem(dp,-1);
int st = 1<<n;
printf("%lld\n",solve(0,0,0));
}
这样就优化到二维dp了