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. jquery mobile跳转到指定id时怎样传递参数

    在jquery mobile 中,每一个页面都是一个page,当我们需要从一个页面跳转到另一个页面时,可以在href中指定id,可是该怎么把一个page中的参数传递到另外一个page中,几经琢磨,发现 ...

  2. 两个常用的功能,将shp数据属性转成TXT和Excel(转)

    //转成txt public static void ConvertTable2Txt(ITable pTable, string pFilePath)        { int pIndex = 0 ...

  3. CentOS7安装小小输入法

    添加epel源 $ sudo yum install epel-release 安装centos7缺失依赖包 libwayland-client $ sudo rpm -Uvh ftp://ftp.p ...

  4. samba服务器与远程登录ssh

    作者:相思羽  出处:http://www.cnblogs.com/xiang-siyu 欢迎转载,也请保留这段声明.谢谢! deepin安装与配置samba服务器 安装  apt-get insta ...

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

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

  6. php之数据类型自动转换

    1:概述 ---php是一种弱类型的语言,它可以根据运行环境的变化而自动进行数据类型的转换 1.1转换成布尔类型的原则 以下值都将转换成布尔类型中的false: A.布尔类型的false; B.空字符 ...

  7. 3dmax使用K帧工具创建一个行走动作

    第一步,创建一个biped骨骼. 这个就不截图了,因为基本都会. 记住一点,先改变了关键点再去修改,不然修改的是前一个关键帧的动作. 第二步,开启自动关键帧,然后给初始位置双脚添加踩踏关键点.设置关键 ...

  8. Unity3D 之3D游戏角色控制器运动

    3D运动,绑定了人形控制器后的一个简单的运动方法. using UnityEngine; using System.Collections; public class PlayerMove : Mon ...

  9. Android 里面的小坑

    1.listview加了个blockdescen,竟然导致editTextView不能获取焦点

  10. Failed to create a 'System.Type' from the text ' ' in wpf(无法从文本创建类型)

    问题描述:WPF is unable to create a type for data templateWPF使用mvvm模式无法加载DataTemplate模板定义的资源,提示无法从文本创建类型错 ...