a题
n, m <= 1e18, p <= 1e5, Lucas定理求组合数
裸的最小生成树
裸的概率dp,令状态dp(i, j)为双方各被锤了i,j次时的期望回合数
贪心,用优先队列进行维护
n, m <= 1e18, p <= 1e5, Lucas定理求组合数
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
ll n, m, p = 100003;
ll f[100005];
ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % p;
b >>= 1;
a = a * a % p;
}
return ans;
}
ll C(ll n, ll m) {
if(m > n) return 0;
ll ans = 1;
for(int i = 1; i <= m; ++i) {
ll a = (n - m + i) % p;
ans = ans * (a * f[i] % p) % p;
}
return ans;
}
ll Lucas(ll n, ll m) {
if(m == 0) return 1;
return C(n % p, m % p) * Lucas(n/p, m/p) % p;
}
int main() {
int t;
cin >> t;
for(int i = 1; i <= p; ++i)
f[i] = qpow(i, p - 2);
while(t--) {
cin >> n >> m;
cout << Lucas(n, m) << endl;
}
}
c题
裸的最小生成树
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005;
typedef long long ll;
int n, m;
struct Edge {
int u, v, val, cost;
Edge(int u, int v = 0, int val = 0, int cost = 0):
u(u), v(v), val(val), cost(cost) { }
bool operator<(const Edge &rhs) const {
return val == rhs.val ? cost < rhs.cost : val > rhs.val;
}
};
vector<Edge> edges;
int p[maxn];
int find(int a) { return p[a] == a ? a : p[a] = find(p[a]); }
bool Kruskal(ll &totval, ll &totcost) {
totval = 0, totcost = 0;
for(int i = 1; i <= n; ++i) p[i] = i;
sort(edges.begin(), edges.end());
int cnt = 0;
for(int i = 0; i < m; ++i) {
Edge e = edges[i];
int x = find(e.u), y = find(e.v);
if(x != y) {
cnt++;
totval += (ll)e.val;
totcost += (ll)e.cost;
p[x] = y;
}
}
return cnt == n - 1;
}
int main() {
int t, kase = 1;
scanf("%d", &t);
while(t--) {
edges.clear();
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++i) {
int u, v, val, cost;
scanf("%d%d%d%d", &u, &v, &val, &cost);
edges.push_back(Edge(u, v, val, cost));
}
ll totval, totcost;
printf("Case #%d: ", kase++);
if(!Kruskal(totval, totcost)) printf("-1\n");
else printf("%lld %lld\n", totval, totcost);
}
return 0;
}
h题
裸的概率dp,令状态dp(i, j)为双方各被锤了i,j次时的期望回合数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 3005;
double dp[maxn][maxn];
bool vis[maxn][maxn];
int cnt1, cnt2;
double p;
double solve(int i, int j) {
if(vis[i][j] == true) return dp[i][j];
vis[i][j] = true;
double &ret = dp[i][j];
if(i >= cnt1 || j >= cnt2) return ret = 0;
ret = (1 - p) * solve(i + 1, j) + p * solve(i, j + 1) + 1.0;
return ret;
}
int main() {
int t;
cin >> t;
while(t--) {
memset(vis, 0, sizeof(vis));
int hp1, hp2, w;
cin >> hp1 >> hp2 >> w;
cin >> p;
cnt1 = (hp1 - 1) / w + 1;
cnt2 = (hp2 - 1) / w + 1;
printf("%.6lf\n", solve(0, 0));
}
return 0;
}
d题
贪心,用优先队列进行维护
#include <iostream>
#include <cstdio>
#include <map>
#include <queue>
using namespace std;
int main() {
int t, kase = 1;
cin >> t;
while(t--) {
int n, k;
cin >> n >> k;
map<int, int> Map;
for(int i = 0, x; i < n; ++i)
cin >> x, Map[x]++;
map<int, int>::iterator it;
priority_queue<int> q;
for(it = Map.begin(); it != Map.end(); ++it)
q.push(it->second);
queue<int> tq;
int ans = 0;
while(q.size() >= k) {
ans++;
for(int i = 0; i < k; ++i) {
int temp = q.top(); q.pop();
tq.push(temp - 1);
}
while(tq.size()) {
int temp = tq.front(); tq.pop();
if(temp > 0) q.push(temp);
}
}
printf("Case #%d:\n", kase++);
cout << ans << endl;
}
return 0;
}