TopCoder SRM469C: TheMoviesLevelThreeDivOne 题解

很好的dp题目
我们尝试推断某一个人A能不间断的看完电影的条件
易得,A想要在看完B的第i-1部电影之后不间断的看B的第i部电影,应该满足以下条件:k=1AtotA[xk]+k=1i1A[yk]k=1iB[yk]0
那我们如果想求A,B均能顺利看完的方案数,考虑dp,大概要记录A的当前和,B的当前和,上面的式子对于A来说的历史最小值和对于B来说的历史最小值,每个状态的级别都是1000的,这样是O(10004)的复杂度,不能接受
考虑怎么优化这个dp
我们可以发现一个性质:A和B中总有一个人能看完所有的电影,因为考虑A和B原来自己手上的电影,总有一个人会先看完自己手上原来的电影,另一个人后看完,那么那个后看完的人看完自己手上原来的电影以后,另一个人的电影一定已经全部看好放在他的队列里面了。也就是说,后看完自己手上原来的的电影的人一定能看完所有的电影
我们考虑用总方案数减去有人被卡住的方案数,由上面一段可知最多只会有一个人卡住,所以答案是AB
这样再用dp算,就可以缩减掉很多状态
令dp[i][j][k]表示当前考虑到第i部电影,对于1~i-1的所有位置,上面的多项式的值的最小值是j,当前的值是k的方案数。注意上面的多项式中的sigma(A)是动态变化的
转移有两种:
1. 第i部电影放入A的queue,那么之前的1~i的所有位置的值由于sigma(A)都要加上a[i],所以dp[i][j][k]dp[i+1][j+a[i]][k+a[i]]
2. 第i部电影放入B的queue,我们考虑用当前的k减去b[i]来更新历史最小值,并且k加上a[i]-b[i]

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=1e9+7;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-10;
const double pi=acos(-1);

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

LL dp[2][2048][2048];
int a[148],b[148];

class TheMoviesLevelThreeDivOne
{
    int n;
    const int MMAX=1000;
    inline LL calc()
    {
        int cur=0,nxt=1,i,j,k;
        memset(dp[0],0,sizeof(dp[0]));
        dp[0][MMAX][MMAX]=1;
        for (i=1;i<=n;i++)
        {
            memset(dp[nxt],0,sizeof(dp[nxt]));
            for (j=MMAX-20*i;j<=MMAX;j++)
                for (k=MMAX-20*i;k<=MMAX+20*i;k++)
                    if (dp[cur][j][k])
                    {
                        //add i to y
                        dp[nxt][min(MMAX,j+b[i])][k+b[i]]+=dp[cur][j][k];
                        //add i to x
                        dp[nxt][min(j,k-a[i])][k+b[i]-a[i]]+=dp[cur][j][k];
                    }
            swap(cur,nxt);
        }
        LL res=0;
        for (j=MMAX-20*n;j<=MMAX-1;j++)
            for (k=MMAX-20*n;k<=MMAX+20*n;k++)
                res+=dp[cur][j][k];
        return res;
    }                   
    public:
        inline LL find(vector<int> A,vector<int> B)
        {
            n=int(A.size());int i;
            for (i=1;i<=n;i++) a[i]=A[i-1],b[i]=B[i-1];
            LL res=calc();
            for (i=1;i<=n;i++) swap(a[i],b[i]);
            res+=calc();
            return (1ll<<n)-res;
        }
};

/*---Debug Part---*/
int main ()
{
    TheMoviesLevelThreeDivOne A;
    int nn;vector<int> aa,bb;
    while (scanf("%d",&nn)!=EOF)
    {
        register int i,x;
        aa.clear();bb.clear();
        for (i=1;i<=nn;i++) x=getint(),aa.pb(x);
        for (i=1;i<=nn;i++) x=getint(),bb.pb(x);
        printf("%lld\n",A.find(aa,bb));
    }
    return 0;
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页