2019 ICPC Malaysia National F(状态压缩)

2019 ICPC Malaysia National F

赛后补题。看了这个题解,说是状态压缩。

以第一行的士兵为主,第二行士兵为次,即,第二行被第一行士兵匹配,更新第一行士兵的状态。

用当前第i个士兵的状态更新第i+1个士兵的状态。

f[i][j]:i为士兵的下标,j为第i个士兵的状态。(1<j<(1<<(e*2+1)))。

比如e=3,二进制 j=1000011,表示第i个士兵之前包括第i个士兵,在[i-3,i+3]范围内,第二行的士兵已被匹配了下标为i-3,i+2,i+3的士兵。而f[i][1000011]记录的则是此状态的个数

那么,第一行的i+1士兵可以 以j=1000011 可更新出f[i+1][0000111],f[i+1][001110],f[i+1][0010110],f[i+1][0100110],f[i][1000110],其中判断是否    **符合“不匹配”关系**,符合则不累加,不符合则可在状态中累加i的状态。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define debug printf("!")
using namespace std;
typedef __int64 ll;
const int mod=1e9+7;
const int maxn=2e3+5;
const int inf=0x3f3f3f3f;
ll f[maxn][1<<10]={0};
int cant[maxn]={0};
inline int calleft(int x,int e)
{
    for(int i=2*e;i>=0;i--)if((1<<i)&x)return e-i;
    return 0;
}
inline int calright(int x,int e)
{
    for(int i=0;i<=2*e;i++)if((1<<i)&x)return e-i;
    return 0;
}
int main()
{
    int n,e,k,i,j,u,v;
    scanf("%d%d%d",&n,&e,&k);
    for(i=1;i<=k;i++)
    {
        scanf("%d%d",&u,&v);
        if(u-v>e||v-u>e)continue;
        cant[u]|=1<<(e+u-v);
    }
    for(i=0;i<=e;i++)
    {
        if(1+e-i>n)continue;
        if((1<<i)&cant[1])continue;
        f[1][1<<i]=1;
    }
    for(i=1;i<n;i++)
    {
        for(j=1;j<1<<(e*2+1);j++)
        {
            if(i+calleft(j,e)<1)break;
            if(i+calright(j,e)>n)continue;
            v=j;
            if(v&(1<<(2*e)))v-=(1<<(2*e));
            v<<=1;
            for(u=0;u<=e*2;u++)
            {
                if(i+1+e-u>n||i+1+e-u<1)continue;
                if((1<<u)&v||(1<<u)&cant[i+1])continue;
                f[i+1][v|(1<<u)]=(f[i+1][v|(1<<u)]+f[i][j])%mod;
            }
        }
    }
    ll ans=0;
    for(i=1;i<1<<(e*2+1);i++)ans=(ans+f[n][i])%mod;
    printf("%I64d\n",ans);
}

2019-09-06

原文地址:https://www.cnblogs.com/kkkek/p/11470628.html

时间: 2024-07-29 22:56:44

2019 ICPC Malaysia National F(状态压缩)的相关文章

2019 ICPC Malaysia National G(拓扑排序)

2019 ICPC Malaysia National G 有点绕,两层拓扑排序. 有空再补详细. 甚至有点丑,因为绕,为了区分,当时变量名写得很长. #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<vector> #define debug printf("!") using namespace std; type

2019 ICPC Malaysia National H题

题意:给定n个点,求出这些点构成的凸包,然后逆时针输出,另外还有q次询问,每次询问一个点是否在凸包里. 题解:二维凸包裸题,直接利用叉积判断点是否在凸包内即可,时间复杂度n2,不知为何这题给了15s,然后我代码只跑了15ms #include <bits/stdc++.h> using namespace std; double eps=1e-15; double pi=acos(-1); struct Point{ double x,y; Point(double x=0,double y=

【上海交大oj】邮递员小F(状态压缩dp)(旅行商问题)

1088. 邮递员小F Description 因为制造类专业很难在大城市立足,曾经立志振兴中华之工业的小F,果断在本科毕业后转行做了一名光荣的邮递员. 他的任务是每天从总局出发,行走于所管辖区域的若干的邮局,收集所有的信,然后再汇总返回总局. 因为工作繁忙,同一个邮局他每天只希望去一次. 来往于任意两个邮局是有一定代价的.而且为了方便统计,假定来回两条道路上的代价假设是一样的. 现在小F希望你能给出他每天的最优行走方案,使得总的代价最少. Input Format 输入数据包括两部分. 第一行

【算法学习笔记】62.状态压缩 DP SJTU OJ 1088 邮递员小F

状态压缩,当我们的状态太多时可以考虑用bit来存储,用二进制来表示集合,用&来取交集,用^来异或. DP过程很简单,遍历所有情况取最短路径就行,因为最短哈密顿回路本身就是一个NPC问题,效率不高. #include <vector> #include <iostream> using namespace std; //最短哈密顿回路问题 NP完全问题... int map[16][16]={0}; int n=0; const int INF=768000;//3000*1

ACM/ICPC 之 BFS+状态压缩(POJ1324(ZOJ1361))

求一条蛇到(1,1)的最短路长,题目不简单,状态较多,需要考虑状态压缩,ZOJ的数据似乎比POj弱一些 POJ1324(ZOJ1361)-Holedox Moving 题意:一条已知初始状态的蛇,求其到(1,1)的最短路长 题解:开始做的时候用BFS暴力做了一次,结果RE了,后来看了其他的题解和discuss才转向状态压缩.也看到有人用A*做出来了. 现在简要介绍一下状态压缩的思路: 由于蛇身最长只有8,可以利用两条相邻蛇身坐标确定其相对方向(四个方向),两位二进制可以表示 这样 一个蛇头坐标+

[ACM] HDU 5025 Saving Tang Monk (状态压缩,BFS)

Saving Tang Monk Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 941    Accepted Submission(s): 352 Problem Description <Journey to the West>(also <Monkey>) is one of the Four Great Clas

uva 818(dfs+图+状态压缩)

题意:有n个环,编号从1到n,给出了一些环环相扣的情况,比如给a和b表示a和b两个环的扣在一起的,每个环都是可以打开的,问最少打开多少个环,然后再扣好,可以让所有的环成为一条链. 题解:状态压缩把所有的打开环的情况枚举出来,然后拿去判断是否成立,更新打开环后的图g[i][j],和每个点的度数,不成立有三种情况,1.计算没有打开的环的度数,如果大于2说明不会有链,2.把没有打开环拿去dfs,访问过就vis[i]++,如果vis[i]>=2说明存在环,3.如果打开的环数num + 1小于链的数量,说

dp状态压缩

dp状态压缩 动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划问题,这个就更加的难于把握了.难点在于以下几个方面:状态怎么压缩?压缩后怎么表示?怎么转移?是否具有最优子结构?是否满足后效性?涉及到一些位运算的操作,虽然比较抽象,但本质还是动态规划.找准动态规划几个方面的问题,深刻理解动态规划的原理,开动脑筋思考问题.这才是掌握动态规划的关键. 动态规划最关键的要处理的问题就是位运算的操作,容易出错,状态的设计也直

2017盛大游戏杯 零件组装(状态压缩DP之巧妙枚举子集)

题目链接:2017盛大游戏杯 零件组装 题意: 有n个零件,给你相邻关系和排斥关系,每两块零件组装起来有一个代价,问最少的代价总和是多少. 题解: 考虑状态压缩,dp[i]表示i这个集合为一个零件块. 那么要枚举一下i的子集.O(3^n). 先要预处理一下每个集合的排斥个数和相邻个数,然后容斥一下就可以了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int