2048
Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 840 Accepted Submission(s): 199
Problem 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.
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).
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: 8HintIn the first case, we should choose all the numbers. In the second case, all the subsequences which contain more than one number are good.
Source
题意:
给你n个数。从中选择一些数能构成一个序列,对于一个序列。能够进行这种操作:选择两个同样的数。将它们替换为它们的和。假设一个序列能够得到2048。那么就说这个序列式good的。问这n个数有多少个子序列是good 的。
思路:
由于每次选择同样的两个数变为他们的和,终于变为2048,所以仅仅有2的幂是有效的,其它的数(tot个)每一个都有两种状态。加或者不加,最后的种数*2^tot。
问题变为给你一些2的幂,问有多少种选取方式终于可变为2048或者2048以上。
能够联想的dp+组合。
dp[i][j]表示处理到2^i,和为[j*2^i,(j+1)*2^i )的个数,枚举选取k个2^(i+1)进行转移就可以。
算2048或者2048以上的状态时间复杂度较高,所以能够算出小于2048的状态。总方案数减去它即可了。
此题时间卡的紧,须要预处理出来逆元。组合数自己递推的时候除法变为乘法。然后还要加输入优化~
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #include <sstream> #define maxn 100005 #define MAXN 100005 #define mod 998244353 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-8 typedef long long ll; using namespace std; int n,m,tot; int mp[2050],cnt[13],p[13],ed[13]; ll ans,dp[13][2050]; ll inv[100005]; int a[12]= {2048,1024,512,256,128,64,32,16,8,4,2,1}; void scanf_(int&ret) { char c; ret=0; while((c=getchar())<'0'||c>'9'); while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar(); } ll pow_mod(ll x,ll n) { ll res = 1; while(n) { if(n&1) res = res * x %mod; x = x * x %mod; n >>= 1; } return res; } void egcd(ll a,ll b,ll &x,ll &y) { if (b==0) { x=1,y=0; return ; } egcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*x; } void solve() { int i,j,k; memset(dp,0,sizeof(dp)); for(i=0; i<=11; i++) { ed[i]=min(cnt[i],a[i]-1); } dp[0][0]=1; ll h=1; for(i=1; i<=ed[0]; i++) { h=((h*(cnt[0]-i+1))%mod)*inv[i]%mod; dp[0][i]=h; } for(i=0; i<11; i++) { for(j=0; j<a[i]; j++) { if(!dp[i][j]) continue ; h=1; dp[i+1][j>>1]+=dp[i][j]; dp[i+1][j>>1]%=mod; for(k=1; k<=ed[i+1]; k++) { if((j>>1)+k<a[i+1]) { h=((h*(cnt[i+1]-k+1))%mod)*inv[k]%mod; dp[i+1][(j>>1)+k]+=h*dp[i][j]; dp[i+1][(j>>1)+k]%=mod; } else break ; } } } ans=((pow_mod(2,n-tot)-dp[11][0]+mod)%mod)*pow_mod(2,tot); ans%=mod; } int main() { int i,j,u,test=0; for(i=1; i<=100000; i++) { ll x,y; egcd(i,mod,x,y); x=(x+mod)%mod; inv[i]=x; } memset(mp,-1,sizeof(mp)); p[0]=1; mp[1]=0; for(i=1; i<=11; i++) { p[i]=p[i-1]*2; mp[p[i]]=i; } while(1) { scanf_(n); if(n==0) break ; tot=0; memset(cnt,0,sizeof(cnt)); for(i=1; i<=n; i++) { scanf_(u); if(mp[u]!=-1) cnt[mp[u]]++; else tot++; } solve(); printf("Case #%d: %I64d ",++test,ans); } return 0; } /* 11 256 256 256 256 256 256 512 512 1024 1024 2048 */
版权声明:本文博主原创文章。博客,未经同意不得转载。