【高维前缀和】SPOJ(TLE)[Time Limit Exceeded]题解

题目概述

题目名称要不要这么奇葩而且和题面没有半毛钱关系啊,我上交题目都以为自己TLE了。

给出 n n 个数 ci ,现在需要构造 ai a i 使得:

  1. ai mod ci>0 a i   m o d   c i > 0
  2. ai and ai+1=0 a i   a n d   a i + 1 = 0

解题报告

先不考虑 ci c i ,那么我们很容易想到DP: f[i][j] f [ i ] [ j ] 表示前 i i 个数第 i 个是 j j 的方案数。

直接枚举肯定不科学,观察 ai and ai+1=0 ,其实是个经典的高维前缀和求超集( y y x 的超集且 y and z=0 y   a n d   z = 0 意味着 x and z=0 x   a n d   z = 0 ,即 y y 包含 x )问题。

但如何处理 ci c i ?其实就在每次转移之后把 j mod ci=0 j   m o d   c i = 0 的状态 j j 赋值为 0 就行了。

示例程序

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=50,maxs=32768,MOD=1e9;

int te,n,m,c[maxn+5],f[maxn+5][maxs+5],ans;

inline void AMOD(int &x,int tem) {if ((x+=tem)>=MOD) x-=MOD;}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    for (scanf("%d",&te);te;te--)
    {
        scanf("%d%d",&n,&m);for (int i=1;i<=n;i++) scanf("%d",&c[i]);
        memset(f,0,sizeof(f));for (int s=0;s<(1<<m);s++) if (s%c[1]) f[1][s]=1;
        for (int i=2;i<=n;i++)
        {
            for (int s=0;s<(1<<m);s++) f[i][s]=f[i-1][s^((1<<m)-1)];
            for (int j=0;j<m;j++)
            for (int s=0;s<(1<<m);s++) if (!(s&(1<<j)))
                AMOD(f[i][s],f[i][s|(1<<j)]);
            for (int s=0;s<(1<<m);s++) if (!(s%c[i])) f[i][s]=0;
        }
        ans=0;for (int s=0;s<(1<<m);s++) if (s%c[n]) AMOD(ans,f[n][s]);
        printf("%d\n",ans);
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值