NOI 2015 寿司晚宴 状压DP

本文介绍了一个关于NOI寿司晚宴问题的算法解决方案。问题要求统计两种和谐品尝方案的数量,避免选择美味度互质的寿司。通过压缩质因子并分组讨论,实现了O(n*3^8)的复杂度。

为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴。小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴。

在晚宴上,主办方为大家提供了n1种不同的寿司,编号1,2,3,,n1,其中第种寿司的美味度为i+1(即寿司的美味度为从2n)。

现在小G和小W希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小G品尝的寿司种类中存在一种美味度为x的寿司,小W品尝的寿司中存在一种美味度为y的寿司,而x与y不互质。

现在小G和小W希望统计一共有多少种和谐的品尝寿司的方案(对给定的正整数p取模)。注意一个人可以不吃任何寿司。

题外话:
  上午听某大神讲DP,讲了不少NOI的好(恶心)题(然而基本没有听懂)。结果晚上水NOI2015时就碰到了。
  一开始偷瞄了题目标签,看到状压后很容易想到压质因子,不过看了看顶多拿一半分。感觉应该是(n2n)的做法,但细节想不清楚。。

思路:
  果然只要压n以内的质因子,对所有数按其大于n的因数分组,若没有大于n的因数则单独分组。对于小于n的因子实际上有3种状态,即某一个人选或者都不选,但这样不是很方便,简单起见我们用f[i][j]表示第一个人取的状态为 i ,第二个人取的状态为 j 的方案数。然后一开始就去掉无效状态加以优化(其实不优化也行)。
  然后对于每一组数,显然某个人只要选了其中的一个,另外一个人就一个也不能选,于是我们每次将f复制到 dp[][],转移也就不难推了。处理完一组后再令f[u][v]=dp[u][v]+dp[v][u]f[i][j],表示某一个人选或不选这一组数,由于这两种情况都包含了两人都不选的情况,所以还需要减掉重复
  由于小于n的质数最多只有8个,所以复杂度为O(n38)

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

#define For(i,j,k) for(int i = j;i <= k;i++)
#define Forr(i,j,k) for(int i = j;i >= k;i--)

const int N = 256;
const int Prime[] = {1, 2, 3, 5, 7, 11, 13, 17, 19};

using namespace std;

struct Num{
    int fac, s;

    bool operator < (const Num& A) const{
        return fac < A.fac;
    }

}A[N<<1];

typedef long long LL;

LL f[N][N], dp[N][N], Mod;
int n, Begin[N], Next[N * N], to[N * N], e;

int main(){
    scanf("%d%lld", &n, &Mod);
    For(i,1,n-1){
        int t = i + 1;
        For(j,1,8) while(t % Prime[j] == 0) 
            t /= Prime[j], A[i].s |= 1 << (j - 1);
        A[i].fac = t;
    }
    For(u,0,255) 
        For(v,0,255) 
            if(!(u & v)){
                Next[++e] = Begin[u];
                Begin[u] = e;
                to[e] = v;
            }
    sort(A + 1, A + n);
    f[0][0] = dp[0][0] = 1;
    int l = 1;
    while(l < n){
        int r = l;
        while(A[r+1].fac == A[l].fac && A[l].fac != 1) ++r;
        For(i,l,r)
            Forr(u,255,0) for(int j = Begin[u];j;j = Next[j]){
                int v = to[j];
                if(!(A[i].s & u)) dp[u][v|A[i].s] = 
                    (dp[u][v|A[i].s] + dp[u][v]) % Mod;
            }
        For(u,0,255) 
            for(int j = Begin[u];j;j = Next[j]){
                int v = to[j];
                f[u][v] = 
                    (dp[u][v] + dp[v][u] - f[u][v] + Mod) % Mod;
            }
        For(u,0,255)
            for(int j = Begin[u];j;j = Next[j]) 
                dp[u][to[j]] = f[u][to[j]];
        l = r + 1;
    }
    LL Ans = 0;
    For(u,0,255) For(v,0,255) Ans = (Ans + f[u][v]) % Mod;
    printf("%lld\n", Ans);
    return 0;
}
标题中提及的“BOE-B2-154-240-JD9851-Gamma2.2_190903.rar”标识了一款由京东方公司生产的液晶显示单元,属于B2产品线,物理规格为154毫米乘以240毫米,适配于JD9851型号设备,并采用Gamma2.2标准进行色彩校正,文档生成日期为2019年9月3日。该缩文件内包含的代码资源主要涉及液晶模块的底层控制程序,采用C/C++语言编写,用于管理显示屏的基础运行功能。 液晶模块驱动作为嵌入式系统的核心软件组成部分,承担着直接操控显示硬件的任务,其关键作用在于通过寄存器读写机制来调整屏幕的各项视觉参数,包括亮度、对比度及色彩表现,同时负责屏幕的启动与关闭流程。在C/C++环境下开发此类驱动需掌握若干关键技术要素: 首先,硬件寄存器的访问依赖于输入输出操作,常借助内存映射技术实现,例如在Linux平台使用`mmap()`函数将寄存器地址映射至用户内存空间,进而通过指针进行直接操控。 其次,驱动需处理可能产生的中断信号,如帧缓冲区更新完成事件,因此需注册相应的中断服务例程以实时响应硬件事件。 第三,为确保多线程或进程环境下共享资源(如寄存器)的安全访问,必须引入互斥锁、信号量等同步机制来避免数据竞争。 第四,在基于设备树的嵌入式Linux系统中,驱动需依据设备树节点中定义的硬件配置信息完成初始化与参数设置。 第五,帧缓冲区的管理至关重要,驱动需维护该内存区域,保证图像数据准确写入并及时刷新至显示面板。 第六,为优化能耗,驱动应集成电源管理功能,通过寄存器控制实现屏幕的休眠与唤醒态切换。 第七,针对不同显示设备支持的色彩格式差异,驱动可能需执行色彩空间转换运算以适配目标设备的色彩输出要求。 第八,驱动开发需熟悉液晶显示控制器与主处理器间的通信接口协议,如SPI、I2C或LVDS等串行或并行传输标准。 最后,完成代码编写后需进行系统化验证,包括基础显示功能测试、性能评估及异常处理能力检验,确保驱动稳定可靠。 该源代码集合为深入理解液晶显示控制原理及底层驱动开发实践提供了重要参考,通过剖析代码结构可掌握硬件驱动设计的具体方法与技术细节。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值