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. 需要设置jdk的三处位置:

    需要设置jdk的三处位置:1.tomcat需要一个JDK : Windows--->Preferences--->MyEclipse--->Servers--->Tomcat- ...

  2. sql快速生成大量数据

    先插入一条数据 insert into table(a,b,c,d) values(1,2,3,4) 然后重复执行以下sql语句 没执行一次 数据就会倍增 insert into table(a,b, ...

  3. 简单的实现QQ通信功能(一)

    第一部分:数据库的设计,数据集的建立 一:数据库的设计: 1.用户表:包含用户名.密码.昵称.性别.备注.状态.头像代号和最后登录时间. 2.朋友关系表:自增长列为主键列,用户名和好友名,还有朋友的状 ...

  4. java List交集 并集 差集 去重复并集

    首先定义两个list List list1 =new ArrayList(); list1.add("); list1.add("); list1.add("); Lis ...

  5. java内存分块

     运行时数据区域 Java虚拟机在执行Java的过程中会把管理的内存划分为若干个不同的数据区域.这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,而有的区域则依赖线程的启 ...

  6. ElastciSearch常用APi

    列出所有的索引: GET /_cat/indices?v 删除索引 DELETE /customer?pretty

  7. UITabBarController 初学

    纯代码编写UITabBarController, 不多说,直接见代码 RViewController1 *vc1 = [[RViewController1 alloc]init]; UINavigat ...

  8. windows8 8.1 安装完 ubuntu无法挂载 ntfs分区 解决方法

    windows8 8.1 安装完 ubuntu无法挂载 ntfs分区 解决方法: 最近安装完发现8.1系统后,ubuntu无法加载以前的ntfs分区了,特别是我添加到了/etc/fstab里面了 导致 ...

  9. C++ 变量转换

    atoi,atol,strtod,strtol,strtoul实现类型转换2006-02-13 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://ivanvic.blogb ...

  10. ios专题 - 图片(UIImage)获取方法

    说到图片获取的方法,就得看API文档. UIImage生成实例的方法有: 1)imageNamed 从指定文件返回对象. 这个方法有个比较特殊的地方:该方法首先从系统缓存中寻找该图片,如果有,则从缓存 ...