考试结束后的第一场CF, 诶,功力不够,B,C都出了点小问题,都绿色了还跌,变紫任重而道远。
http://www.codeforces.com/contest/262
A. 暴力
B. 注意要把k次用完,我图快没看清楚,WA了一次。
C. 贪心,q[]数组排序一下,只要取最小的那个q[]去打折,不能打折的分开买,很容易证明这种方案是最优的, 我很早就想到了,当时总觉得这种方案不一定最优,一直再举反例,太失败了, 后来才发现这是最优的,但赛后由于一个小细节在改得时候没改过来RE掉了,诶,无奈跌分。
D . 背包DP, 比赛的时候想到了背包,但本人水平太弱,思路无法构建,赛后看别人代码,很久才吃透为什么要那么做,好题啊,思维又有了提高。
思路:
先处理出dp[i][j](表示排了i个人,占桌子的长度为j的情况有几种)
// 方法一:
dp[0][0] = 1;
double ans = 0;
for(i = 0; i < n; i++)
for(k = p; k >= a[i]; k--)
for(j = 1; j <= i+1; j++)
dp[j][k] += dp[j-1][k-a[i]];
//方法二:
dp[0][0] = 1;
for(i = 0; i < n; i++)
for(j = n; j > 0; j--)
for(k = a[i]; k <= p; k++)
dp[j][k]+=dp[j-1][k-a[i]];
以上两种只是状态转移时先后顺序不同。
预处理以后,我们要想把所有情况都列一遍,所以有一下做法
f[i]*f[n-i]*dp[i][j] 表示计算所有第i位的排列总数
for(i = 1; i <= n; i++)
for(j = 1; j <= p; j++)
ans += f[i]*f[n-i]*dp[i][j];
printf("%.10lf\n", ans/f[n]);
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
double dp[51][51], f[51];
int a[51];
int main()
{
int i, j, k, n, p;
f[0] = 1;
for(i = 1; i <= 50; i++)
f[i] = f[i-1] * i;
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
scanf("%d", &p);
dp[0][0] = 1;
double ans = 0;
for(i = 0; i < n; i++)
for(j = n; j > 0; j--)
for(k = a[i]; k <= p; k++)
dp[j][k]+=dp[j-1][k-a[i]];
// for(i = 1; i <= n; i++)
// for(j = 1; j <= p; j++)
// printf("dp[%d][%d] = %.9f\n", i, j, dp[i][j]);
for(i = 1; i <= n; i++)
for(j = 1; j <= p; j++)
ans += f[i]*f[n-i]*dp[i][j];
printf("%.10lf\n", ans/f[n]);
return 0;
}
E. 观察题目数据, 第m+1层的和肯定有规律, 打表找规律, 但自己找了好久都没找到, 得到大神的结论 sum=2^(bit_count(m+1)-1) (证明不会)。
然后问题转化为: 找2到m+1 表示成二进制的这些数中 各位之和 为 log2 t + 1 的个数, 显然 当 t 不为 2 的 整数倍时, 答案为0。
这不是数位DP吗?
先预处理dp[i][j](表示二进制数位为i,各位数的总和为j 的数有几种)
dp[1][1] = dp[1][0] = 1;
for(i = 2; i <= 53; i++)
{
for(j = 1; j <= i; j++)
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
dp[i][0] = dp[i-1][0];
}
然后逐位降位处理:
数位DP两道入门题:light OJ : http://blog.youkuaiyun.com/c3568/article/details/8504560
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL __int64
int a[55];
LL dp[55][55];
void init()
{
int i, j;
dp[1][1] = dp[1][0] = 1;
for(i = 2; i <= 53; i++)
{
for(j = 1; j <= i; j++)
dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
dp[i][0] = dp[i-1][0];
}
}
void update(LL n, int &num)
{
num = 0;
while(n) {a[num++] = n % 2; n /= 2;}
}
LL gao(LL n, LL t)
{
int tot = 0;
while((t&1) == 0) {t >>= 1; tot++;}
if(t != 1) return 0;
t = tot+1;
int num; update(n, num);
LL ans = 0, cnt = 0;
int i;
for(i = num-1; i >= 0; i--)
{
if(a[i])
{
if(t >= cnt)
ans += dp[i][t-cnt];
cnt++;
}
}
if(t == 1) ans--;
if(cnt == t) ans++;
return ans;
}
int main()
{
int i, j;
LL n, t;
init();
int a;
scanf("%I64d%I64d", &n, &t);
printf("%I64d\n", gao(n+1, t));
return 0;
}