标签:codeforces
题目链接:http://codeforces.com/problemset/problem/525/E
题意:
给定n个数,k个感叹号,常数S
下面给出这n个数。
目标:
任意给其中一些数变成阶乘,至多变k个。
再任意取一些数,使得这些数和恰好为S
问有多少方法。
思路:
三进制状压,0代表不取,1代表取阶乘,2代表直接取;
中途查找,节约空间;
代码如下:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<map> #include<vector> using namespace std; typedef long long ll; ll n, k, s, tmp; ll san[30], jc[1000], a[30]; map<ll, int>mp[2][30]; //2是归属范围 ,0代表前一半,1代表后一半 ll re[30],b[30], d[30], top; ll cal(ll x) { if(x >= tmp) return -1; else return jc[x]; } void work(int x) { for(int i = 0; i < san[top]; i++) { int cnt = 0; //阶乘的个数 ll sum = 0; int t = i, id = 0; while(t) { if(t % 3 == 1) { cnt++; sum += d[id]; if (d[id] < 0) { sum = s + 1; break; } } else if ((t % 3) == 2) { sum += b[id]; } if (cnt > k || sum > s)break; t /= 3; id++; } if (cnt <= k && sum <= s) mp[x][cnt][sum]++; } } int main() { scanf("%I64d%I64d%I64d", &n, &k , &s); san[0] = 1; for(int i = 1; i < 30; i++) { san[i] = san[i-1] * 3; } jc[1] = 1; for(int i = 2; ; i++) { jc[i] = jc[i-1] * i; if(s / jc[i] <= i) { tmp = i+1; break; } } for(int i = 0; i < n ; i++) { scanf("%I64d", &a[i]); re[i] = cal(a[i]); } for(int i = 0; i < n/2; i++) { b[i] = a[i]; d[i] = re[i]; } top = n / 2; work(0); for (int i = n / 2; i < n; i++) { b[i - n / 2] = a[i]; d[i - n / 2] = re[i]; } top = n - n / 2; work(1); ll ans = 0; for(int i = 0; i <= k; i++) { for(map<ll,int>::iterator h = mp[0][i].begin(); h != mp[0][i].end(); h++) { pair<ll, int> it = *h; for (int j = 0; j + i <= k; j++) { if (mp[1][j].count(s - it.first)) ans += (ll)it.second * mp[1][j][s - it.first]; } } } printf("%I64d\n", ans); return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
Codeforces Round #297 (Div. 2)E. Anya and Cubes
标签:codeforces
原文地址:http://blog.csdn.net/doris1104/article/details/46779741