http://codeforces.com/contest/525/problem/E
题意:
有n个方块,上面写着一些自然数,还有k个感叹号可用。k<=n
你可以选任意个方块,然后选一些贴上感叹号使上面的数值变成阶乘,然后把方块上的值加起来会得到一个和。
求和等于S的选择方法数。
思路:折半搜索,然后把所有状态按权值排序,然后统计
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 #define ll long long 7 struct node{ 8 ll v,st; 9 int id,y; 10 }b[3000005],c[3000005]; 11 int tot1,tot2; 12 int n,K,flag,a[200005],d[200005]; 13 ll S,bin[50],jc[50],ans; 14 bool cmp(node a,node b){ 15 return a.v<b.v; 16 } 17 ll read(){ 18 ll t=0,f=1;char ch=getchar(); 19 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 20 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 21 return t*f; 22 } 23 int lowbit(int x){ 24 return (x)&(-x); 25 } 26 bool pd(ll st1,ll st2){ 27 int cnt=0; 28 while (st1){ 29 ll t=st1%3; 30 if (t==2) cnt++; 31 st1/=3; 32 } 33 while (st2){ 34 ll t=st2%3; 35 if (t==2) cnt++; 36 st2/=3; 37 } 38 return cnt<=K; 39 } 40 void dfs(int k,ll st,ll res,int cnt,int lim){ 41 if (k>lim){ 42 if (flag==0){ 43 tot1++; 44 b[tot1].v=res; 45 b[tot1].st=st; 46 b[tot1].id=0; 47 b[tot1].y=cnt; 48 }else{ 49 tot2++; 50 c[tot2].v=res; 51 c[tot2].st=st; 52 c[tot2].id=1; 53 c[tot2].y=cnt; 54 } 55 return; 56 } 57 dfs(k+1,st+bin[k-1]*0,res,cnt,lim); 58 dfs(k+1,st+bin[k-1]*1,res+a[k],cnt,lim); 59 if (a[k]<=19&&res+jc[a[k]]<=S&&cnt+1<=K) 60 dfs(k+1,st+bin[k-1]*2,res+jc[a[k]],cnt+1,lim); 61 } 62 int num(ll x){ 63 int cnt=0; 64 while (x){ 65 ll t=x%3; 66 if (t==2) cnt++; 67 x/=3; 68 } 69 return cnt; 70 } 71 void up(int x,int v){ 72 for (int i=x;i<=K;i++) 73 d[i]+=v; 74 } 75 int ask(int x){ 76 return d[x]; 77 } 78 int main(){ 79 n=read();K=read();S=read(); 80 bin[0]=1; 81 for (int i=1;i<=20;i++) 82 bin[i]=bin[i-1]*3; 83 jc[0]=1; 84 for (int i=1;i<=19;i++) 85 jc[i]=jc[i-1]*i; 86 for (int i=1;i<=n;i++) 87 a[i]=read(); 88 flag=0; 89 dfs(1,0,0,0,(n+1)>>1); 90 flag=1; 91 dfs(((n+1)>>1)+1,0,0,0,n); 92 std::sort(b+1,b+1+tot1,cmp); 93 std::sort(c+1,c+1+tot2,cmp); 94 int j=tot2; 95 for (int i=1;i<=tot1&&j;){ 96 for (;j&&b[i].v+c[j].v>S;j--); 97 if (b[i].v+c[j].v==S){ 98 for (int y=0;y<=K;y++) d[y]=0; 99 for (;i<=tot1&&b[i].v+c[j].v==S;i++) d[b[i].y]++; 100 for (int y=1;y<=K;y++) d[y]+=d[y-1]; 101 for (;j&&b[i-1].v+c[j].v==S;j--) ans+=d[K-c[j].y]; 102 }else i++; 103 } 104 printf("%I64d ",ans); 105 return 0; 106 }