3851: 2048

Time Limit: 2 Sec  Memory Limit: 64 MB
Submit: 22  Solved: 9
[Submit][Status]

Description

Teacher Mai is addicted to game 2048. But finally he finds it's too hard to get 2048. So he wants to change the rule:
You are given some numbers. Every time you can choose two numbers
of the same value from them and merge these two numbers into their sum.
And these two numbers disappear meanwhile.
  
If we can get 2048 from a set of numbers with this operation, Teacher Mai think this multiset is good.
You have n numbers, A1,...,An. Teacher Mai ask you how many subsequences of A are good.
The number can be very large, just output the number modulo 998244353.
 

Input

There are multiple test cases, terminated by a line "0".
For each test case, the first line contains an integer n
(1<=n<=10^5), the next line contains n integers ai
(0<=ai<=2048).

Output

For each test case, output one line "Case #k: ans", where k is the
case number counting from 1, ans is the number module 998244353.

Sample Input

4
1024 512 256 256
4
1024 1024 1024 1024
5
1024 512 512 512 1
0

Sample Output

Case #1: 1
Case #2: 11
Case #3: 8

HINT

In the first case, we should choose all the numbers.
In the second case, all the subsequences which contain more than one number are good.
 
  sro卡常数orz。。。。。。我也不知道为什么,网上比我慢几倍的程序都能秒过。。。。
  题解什么的可以参见hdu4945,我用的是组合数,逆元什么的,具体来说,只有2^i的数是有用的(这个地方有点坑,如果用x==x&(-x)判定,则会把0算进去)然后我是枚举每一个数x选了多少个,顶多2048/x个,用组合数优化背包。但是这个办法还是很慢,经过面目全非的常数优化,八中2500ms过的,hdu就根本过不了了。
  这个方法实在太渣,优化后卡时过的,童鞋们最好用其他方法额。   
顺便总结一下这道题用的常数优化技巧:
  1. register 这次我实践证明register是有作用的
  2. [2][n]的二维数组改成两个数组。
  3. 数组下标索引改成指针。
  4. 如果会多次调用几个数的乘积,可以提前预处理出来。
  5. 改变for语句嵌套顺序,省略for内部的条件判断。
  6. 读入优化x*10可改成 (x<<3)+(x<<2)
  7. 少用取模才是终极目标。
/**************************************************************
Problem: 3851
User: mhy12345
Language: C++
Result: Accepted
Time:2520 ms
Memory:17536 kb
****************************************************************/ #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MOD 998244353
#define MAXN 510000
#define deal(x,y) \
(x)=((x)+(y))%MOD;
inline int nextInt()
{
register int x=;
register char ch;
while (ch=getchar(),ch<'' || ch>'');
while (x=(x<<)+(x<<)+ch-'',ch=getchar(),ch<='' && ch>='');
return x;
}
const int mod=MOD;
typedef long long qword;
qword pow_mod(qword x,qword y)
{
qword ret=;
while (y)
{
if (y&)ret=ret*x%MOD;
x=x*x%MOD;
y>>=;
}
return ret;
}
qword dp[][];
qword fact[MAXN];
int tot[];
qword inv[MAXN];
qword val[MAXN];
pair<int,int> pl[MAXN];
int topp=-;
int main()
{
//freopen("input.txt","r",stdin);
register int i,j,k,k2;
int x,y,z,n,m;
int nn;
fact[]=;
for (i=;i<MAXN;i++)
fact[i]=fact[i-]*i%MOD;
inv[]=;
for (i=;i<MAXN;i++)
inv[i]=pow_mod(fact[i],MOD-);
int cnt=;
register qword *dp1,*dp2;
register qword a=;
while (scanf("%d",&n),cnt++,n)
{
printf("Case #%d: ",cnt);
memset(dp[],,sizeof(dp[]));
memset(tot,,sizeof(tot));
dp[][]=;
for (i=;i<=n;i++)
{
x=nextInt();
tot[x]++;
}
int ttr=;
for (i=;i<=;i++)
if (!i || i!=(i&(-i)))
ttr+=tot[i];
int cnt=;
bool flag=false;
for (i=;i<=;i<<=,cnt^=flag)
{
memset(dp[cnt^],,sizeof(dp[cnt^]));
dp1=dp[cnt];
dp2=dp[cnt^];
flag=false;
if (!tot[i])continue;
flag=true;
for (j=;j<=tot[i];j++)
val[j]=*(fact+*(tot+i)) * *(inv+j)%MOD * *(inv+tot[i]-j)%MOD;
for (a=,j=/i+(%i!=);j<=tot[i];j++)
a=(a+ * (val+j))%MOD;
for (k=;k>=;k--)
if (dp1[k])
{
for (j=,k2=k;j<=tot[i] && k2<;j++,k2+=i)
deal(dp2[k2],*(dp1+k) * *(val+j));
qword &b=dp2[];
k2-=k;
for (;k2< && j<=tot[i];j++,k2+=i)
deal(b,*(dp1+k)* *(val+j));
if (j<=tot[i])
deal(b,*(dp1+k)*a);
}
}
printf("%lld\n",dp[cnt][]*pow_mod(,ttr)%MOD);
}
}

面目全非版

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MOD 998244353
#define MAXN 510000
#define deal(x,y) \
(x)=((x)+(y))%MOD;
inline int nextInt()
{
register int x=;
register char ch;
while (ch=getchar(),ch<'' || ch>'');
while (x=(x<<)+(x<<)+ch-'',ch=getchar(),ch<='' && ch>='');
return x;
}
const int mod=MOD;
typedef long long qword;
qword pow_mod(qword x,qword y)
{
qword ret=;
while (y)
{
if (y&)ret=ret*x%MOD;
x=x*x%MOD;
y>>=;
}
return ret;
}
qword dp[][];
qword fact[MAXN];
int tot[];
qword inv[];
pair<int,int> pl[MAXN];
int topp=-;
int main()
{
freopen("input.txt","r",stdin);
int i,j,k,x,y,z,n,m;
int k2;
int nn;
fact[]=;
for (i=;i<MAXN;i++)
fact[i]=fact[i-]*i%MOD;
inv[]=;
for (i=;i<MAXN;i++)
inv[i]=pow_mod(fact[i],MOD-);
int a1,a2;
int cnt=;
while (scanf("%d",&n),cnt++,n)
{
printf("Case #%d: ",cnt);
memset(dp,,sizeof(dp));
memset(tot,,sizeof(tot));
dp[][]=;
for (i=;i<=n;i++)
{
x=nextInt();
tot[x]++;
}
int ttr=;
for (i=;i<=;i++)
if (!i || i!=(i&(-i)))
ttr+=tot[i];
int cnt=;
bool flag=false;
for (i=;i<=;i<<=,cnt^=flag)
{
memset(dp[cnt^],,sizeof(dp[cnt^]));
flag=false;
if (!tot[i])continue;
flag=true;
qword a=;
for (j=/i+(%i!=);j<=tot[i];j++)
a=(a+inv[j]*inv[tot[i]-j])%MOD;
a=a*fact[tot[i]]%MOD;
for (k=;k>=;k--)
if (dp[cnt][k])
{
for (j=,k2=k;j<=tot[i] && k2<;j++,k2+=i)
deal(dp[cnt^][k2],dp[cnt][k]*fact[tot[i]]%MOD*inv[j]%MOD*inv[tot[i]-j]);
qword &b=dp[cnt^][];
k2-=k;
for (;k2< && j<=tot[i];j++,k2+=i)
deal(b,dp[cnt][k]*fact[tot[i]]%MOD*inv[j]%MOD*inv[tot[i]-j]);
if (j<=tot[i])
deal(dp[cnt^][],dp[cnt][k]*a);
}
}
printf("%lld\n",dp[cnt][]*pow_mod(,ttr)%MOD);
}
}

TLE版

bzoj 3851: 2048 dp优化的更多相关文章

  1. NOIP2015 子串 (DP+优化)

    子串 (substring.cpp/c/pas) [问题描述] 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重 叠 的非空子串,然后把这 k 个子串按照其在字 ...

  2. LCIS tyvj1071 DP优化

    思路: f[i][j]表示n1串第i个与n2串第j个且以j结尾的LCIS长度. 很好想的一个DP. 然后难点是优化.这道题也算是用到了DP优化的一个经典类型吧. 可以这样说,这类DP优化的起因是发现重 ...

  3. HDU 4945 2048(DP)

    HDU 4945 2048 题目链接 题意:给定一个序列,求有多少个子序列能合成2048 思路:把2,4,8..2048这些数字拿出来考虑就能够了,其它数字不管怎样都不能參与组成.那么在这些数字基础上 ...

  4. 取数字(dp优化)

    取数字(dp优化) 给定n个整数\(a_i\),你需要从中选取若干个数,使得它们的和是m的倍数.问有多少种方案.有多个询问,每次询问一个的m对应的答案. \(1\le n\le 200000,1\le ...

  5. dp优化1——sgq(单调队列)

    该文是对dp的提高(并非是dp入门,dp入门者请先参考其他文章) 有时候dp的复杂度也有点大...会被卡. 这几次blog大多数会讲dp优化. 回归noip2017PJT4.(题目可以自己去百度).就 ...

  6. loj6171/bzoj4899 记忆的轮廊(期望dp+优化)

    题目: https://loj.ac/problem/6171 分析: 设dp[i][j]表示从第i个点出发(正确节点),还可以有j个存档点(在i点使用一个存档机会),走到终点n的期望步数 那么 a[ ...

  7. 常见的DP优化类型

    常见的DP优化类型 1单调队列直接优化 如果a[i]单调增的话,显然可以用减单调队列直接存f[j]进行优化. 2斜率不等式 即实现转移方程中的i,j分离.b单调减,a单调增(可选). 令: 在队首,如 ...

  8. 【学习笔记】动态规划—各种 DP 优化

    [学习笔记]动态规划-各种 DP 优化 [大前言] 个人认为贪心,\(dp\) 是最难的,每次遇到题完全不知道该怎么办,看了题解后又瞬间恍然大悟(TAT).这篇文章也是花了我差不多一个月时间才全部完成 ...

  9. Codevs 1305 Freda的道路(矩阵乘法 DP优化)

    1305 Freda的道路 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description Freda要到Rainbow的城堡去玩了.我们可以认 ...

随机推荐

  1. SpringMVC——项目启动时从数据库查询数据

    SpringMVC项目中遇到这样的问题: 1.很多数据字典需要从数据库中查询: 2.懒得修改SQL语句: 3.想在项目中声明静态变量存储数据字典,但是希望这个字典可以在项目启动时进行加载. 当遇到这样 ...

  2. Android Studio快捷键指南(本文持续更新)

    这是我在使用Android Studio过程中接触到的一些快捷键,和大家分享,后面会继续完善此文,也欢迎大家踊跃补充,一起完善. 快捷键 删除并剪贴行:Ctrl+X 复制一行:Ctrl+D 代码格式整 ...

  3. 微信小程序的一些限制

    小程序的一些限制: 不支持HTML.没有 Dom.网页用的 JS.CSS 基本要全部重写,WXML 的语法和 HTML 差异还挺大,基本是一个个照着手册的属性去改.CSS 选择器不支持级联. 小程序源 ...

  4. 布隆过滤器(Bloom Filter)

    一.布隆过滤器介绍 Bloom Filter是一种空间效率很高的随机数据结构,Bloom Filter可以看做是对bit-map的扩展,它的原理如下: 当一个元素被加入集合时,通过K个Hash函数将这 ...

  5. modelsim打开.wlf文件的方法(原创)

    运行vsim -c -l vsim.log -wlf vsim.wlf work.tb work.glbl之后,会在不启动modelsim的情况下完成仿真,并且会把仿真波形记录下来(以.wlf文件格式 ...

  6. "make_path" is not exported by the File::Path modul

    之前正常运行的perl脚本换了一个环境突然报 从原来的make_path 和 remove_tree改为现在的mkpath 和 rmtree就好了. File::Path version is 1.0 ...

  7. GridView中使用如下button OnClientClick代码会出现解析错误

    在GridView中使用如下代码会出现解析错误: <asp:LinkButton ID="DeleteButton" runat="server" Cau ...

  8. linux字符过滤

    1  案例一:取eth0的IP地址 方法一:通过cut方法过滤 [root@baiguin ~]# ifconfig eth0|grep "inet addr:"|cut -d & ...

  9. javascript 获取url参数

    /** window.location.search获取url地址?以后的值 获取url参数有两种方法,第一种如下,第二种是通过正则 */ //基本版 function getParam() { va ...

  10. MongoDB源码分析——mongo主程序入口分析

    Edit   源码版本为MongoDB 2.6分支 mongo主程序入口分析 mongo是MongoDB提供的一个执行JavaScript脚本的客户端工具,可以用来和服务端交互,2.6版本的Mongo ...