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. Android Activiy的作用

    在Android应用程序中 ,Activity主要的负责创建窗口的,一个Activicy就是代表一个单独的屏幕,并且是用户唯一可以看到的东西 也就是说Activity就是用来实现和用户交互的,就和.n ...

  2. day-1

    /* 倒计时就要结束了 在机房的最后一个晚上 恩 就要结束了 上午考试 下午背板 找了几个原题敲了敲 晚上zjk老妈送的饭 撑死死死死了 好吃23333 吃饭完和zjk在机房门口楼梯上聊了一会 恩 以 ...

  3. C#用副线程改主线程(UI线程)的控件属性的方法(包括Winform和WPF)

    C#用副线程去试图修改主线程的UI控件会报出异常,解决方案是使用副线程注册事件通知主线程自己去修改UI控件 在winform中,方法如下 private void button1_Click(obje ...

  4. 一个react的完整项目展示

    和一些人的关系像平行线,一辈子相守相望,见于眼底藏于心间.就怕耐不住寂寞,冲动而成了相交线,在一个点尽情拥抱,从此便离得越来越远,再也不见.遇到这样的人,因为不想做恋人只能一时,所以才选择做朋友能一世 ...

  5. java Spring集合

    在进行输入的时候一定要给属性配置set方法,因为不设置是注入不了的. 1.list UserService.java private ArrayList arr; public ArrayList g ...

  6. Android免坑指南(一)Sugar与SQLite

    最近在Android手机开发中使用了ORM框架Sugar1.4,节省了大量代码,同时也遇到不少麻烦,记录如下: 1. 使用group by将查询结果转换为POJO对象 在Sugar1.4中,可以使用如 ...

  7. mongodb write 【摘自网上,只为记录,学习】

    mongodb有一个write concern的设置,作用是保障write operation的可靠性.一般是在client driver里设置的,和db.getLastError()方法关系很大 一 ...

  8. bzoj1231: [Usaco2008 Nov]mixup2 混乱的奶牛

    思路:状压dp,设f[i][j]表示当前已经选出的牛的状态为i,最后一头选出的牛为j的方案数. 然后注意就是初值不能是f[0][i]=1,因为所有牛本来都可以第一个被选中,然而这样一定初值有些牛可能就 ...

  9. itoa : Convert integer to string

      Quote from:  http://www.cplusplus.com/reference/cstdlib/itoa/   function   Required header : <s ...

  10. C++类继承内存布局(二)

    转自:http://blog.csdn.net/jiangyi711/article/details/4890889# (二 )成员变量 前面介绍完了类布局,接下来考虑不同的继承方式下,访问成员变量的 ...