1003 玩骰子
暴力枚举抛的骰子的点数,算出获胜的方案数,然后在三个里面选择最大值。
#include <bits/stdc++.h>
using namespace std;
int a[4], b[4];
bool all_same(int *c) {
return (c[1] == c[2] && c[2] == c[3]);
}
bool two_same(int *c) {
return (c[1] == c[2] || c[2] == c[3]);
}
bool ok(void) {
if (all_same (a)) {
if (!all_same (b)) return true;
else {
if (all_same (b) && a[1] > b[1]) return true;
}
}
else if (two_same (a) && !all_same (a)) {
int x1 = a[1], y1= a[3];
if (a[2] == a[3]) swap (x1, y1);
if (!all_same (b) && !two_same (b)) return true;
else if (two_same (b) && !all_same (b)) {
int x2 = b[1], y2 = b[3];
if (b[2] == b[3]) swap (x2, y2);
if (x1 > x2) return true;
else if (x1 == x2 && y1 > y2) return true;
}
}
else {
if (!all_same (b) && !two_same (b)) {
if (a[3] > b[3]) return true;
else if (a[3] == b[3]) {
if (a[2] > b[2]) return true;
else if (a[2] == b[2]) {
if (a[1] > b[1]) return true;
}
}
}
}
return false;
}
int run(int id) {
int ret = 0;
int c[4];
for (int i=1; i<=3; ++i) c[i] = a[i];
for (int i=1; i<=6; ++i) {
for (int j=1; j<=3; ++j) {
a[j] = c[j];
}
a[id] = i;
sort (a+1, a+1+3);
if (ok ()) ret++;
}
for (int i=1; i<=3; ++i) a[i] = c[i];
return ret;
}
int main(void) {
int T; scanf ("%d", &T);
while (T--) {
for (int i=1; i<=3; ++i) scanf ("%d", &a[i]);
for (int i=1; i<=3; ++i) scanf ("%d", &b[i]);
sort (a+1, a+1+3); sort (b+1, b+1+3);
if (ok ()) {
printf ("1.000\n"); continue;
}
double ans = 0;
for (int i=1; i<=3; ++i) {
int cnt = run (i);
ans = max (ans, cnt / 6.0);
}
printf ("%.3f\n", ans);
}
return 0;
}
1005 ACM组队安排
两种做法:1. 递推公式,可以从n-1中选择0, 1, 2个人,然后乘上dp[n-i]的方案
2. 排列组合,
计算公式:f[n]=∑{ com(n,i)*com(n-i,j*2)*equa(j*2,2)/fac[j]*equa(k*3,3)/fac[k] },(i+2*j+3*k=n)
一人一组:com(n,i) 从n个人中选i个人
两人一组:com(n-i,j*2)*equa(j*2,2)/fac[j] 从n-i个人中选出2*j个人,并且将这2*j个人无序地平分成j组
三人一组:equa(k*3,3)/fac[k] ,将剩余的3*k个人无序地平分成k组
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
int fact[15];
int comb[22][22];
ll dp[21];
ll equa(int n, int m) {
ll ret = 1;
while (n) {
ret *= comb[n][m];
n -= m;
}
return ret;
}
void Comb(void) {
for (int i=0; i<21; ++i) {
comb[i][i] = comb[i][0] = 1;
for (int j=1; j<i; ++j) {
comb[i][j] = comb[i-1][j] + comb[i-1][j-1];
if (comb[i][j] >= MOD) {
comb[i][j] -= MOD;
}
}
}
}
void init(void) {
Comb ();
fact[0] = fact[1] = 1;
for (int i=2; i<=13; ++i) {
fact[i] = fact[i-1] * i;
}
for (int i=0; i<=20; ++i) {
for (int j=0; j<=10; ++j) {
for (int k=0; k<=6; ++k) {
if (i + 2 * j + 3 * k <= 20) {
int m = i + 2 * j + 3 * k;
dp[m] += comb[m][i] * comb[m - i][2 * j] * equa (2 * j, 2) / fact[j] * equa (3 * k, 3) / fact[k];
}
}
}
}
}
void solve(void) {
dp[1] = 1; dp[2] = 2; dp[3] = 5; dp[4] = 14;
for (int i=5; i<=20; ++i) {
dp[i] = dp[i-1] + (i - 1) * dp[i-2] + (i - 1) * (i - 2) / 2 * dp[i-3];
}
}
int main(void) {
//init ();
solve ();
int n;
while (scanf ("%d", &n) == 1) {
if (!n) break;
printf ("%I64d\n", dp[n]);
}
return 0;
}
1006 逆袭指数
暴力枚举sqrt (n)的长度
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
int ans[N], v[N];
int mx;
void DFS(int n, int m, int len) {
if (n % m == 0) {
v[len] = m;
DFS (n / m, m + 1, len + 1);
}
else if (len > mx) {
mx = len;
for (int i=0; i<len; ++i) ans[i] = v[i];
}
}
int main(void) {
int n;
while (scanf ("%d", &n) == 1) {
mx = 0;
int k = sqrt (n) + 2;
for (int i=2; i<=k; ++i) {
DFS (n, i, 0);
}
if (!mx) {
printf ("1\n%d\n", n); continue;
}
printf ("%d\n", mx);
printf ("%d", ans[0]);
for (int i=1; i<mx; ++i) {
printf ("*%d", ans[i]);
}
puts ("");
}
return 0;
}