A.礼物
题意:有n种1元礼物和m种2元礼物 你有k元你能搭配出多少种组合
题解:他们都写的背包 发现我不会
就枚举买几个1元的礼物 剩下部分买2元的 然后用组合数学搞搞
#include <stdio.h> #include <algorithm> #include <iostream> using namespace std; typedef long long ll; ll f[2005][2005]; void fun(ll mod) { for(int i = 0; i <= 2000; i++) f[i][0] = 1LL; for(int i = 1; i <= 2000; i++) { for(int j = 1; j <= i; j++) f[i][j] = (f[i - 1][j - 1] + f[i - 1][j]) % mod; } } int main() { int T; scanf("%d", &T); while(T--) { ll n, m, k, p; cin>>n>>m>>k>>p; fun(p); ll ans = f[k + n - 1][k]; if(m != 0) { for(int i = 1; i < k; i++) { if((k - i) & 1) continue; int j = (k - i) >> 1; ans = (ans + f[i + n - 1][i] * f[j + m - 1][j] % p) % p; } } if(k % 2 == 0) ans = (ans + f[k / 2 + m - 1][k / 2]) % p; printf("%lld ", ans); } return 0; }
B.麻婆豆腐
题意:给出n枚硬币正面朝上的概率 求有多少子集使得硬币正面朝上次数为奇数的概率等于偶数
题解:发现对于一个集合 如果有正面朝上概率为0.5的硬币 那么其余硬币随便怎么搞都满足
比如我们要求正面朝上的概率为奇数的个数 假设除了0.5的硬币其他硬币为奇数的概率为p 为偶数的概率为1-p
那么p为奇数 = p*0.5 + (1 - p)*0.5 所以含有0.5正面朝上概率硬币的子集一定满足
#include <stdio.h> #include <algorithm> #include <iostream> #include <cmath> using namespace std; typedef long long ll; int main() { int T; scanf("%d", &T); while(T--) { int cnt = 0; int n; cin>>n; double x; for(int i = 1; i <= n; i++) { cin>>x; if(fabs(x - 0.5) < 1e-7) cnt++; } ll ans = ((1LL << (ll)cnt) - 1LL) * (1LL << (ll)(n - cnt)); printf("%lld ", ans); } return 0; }
C.寻宝
题意:n个点 每个点能到达另外一个点 选择一个点作为起点 能最多经历多少不同的点
题解:n个点n条边 那么这一定是由一些带环树组成的 dfs找出每一块然后记忆化更新答案
#include <stdio.h> #include <algorithm> #include <iostream> #include <vector> using namespace std; const int maxn = (1 << 24) + 5; typedef long long ll; vector<int> g; int to[maxn]; int dp[maxn]; int vis[maxn]; int st; void dfs(int x) { dp[x] = 1; vis[x] = -1; int v = to[x]; if(v == x) { vis[x] = 1; return; } if(vis[v] == 1) dp[x] += dp[v]; else if(vis[v] == 0) { dfs(v); if(st == -1) dp[x] += dp[v]; else if(x == st) { g.push_back(x); int tmp = g.size(); for(int i = 0; i < g.size(); i++) dp[g[i]] = tmp; st = -1; g.clear(); } else g.push_back(x); } else if(vis[v] == -1) st = v, g.push_back(x); vis[x] = 1; } int main() { int T; scanf("%d", &T); while(T--) { st = -1; ll a, b, c, n; cin>>a>>b>>c>>n; for(ll i = 0; i < n; i++) { dp[i] = 0; vis[i] = 0; to[i] = (a * i * i + b * i + c) % n; to[i] = (to[i] + n) % n; } int ans = 0; for(int i = 0; i < n; i++) { if(!vis[i]) dfs(i); ans = max(ans, dp[i]); } printf("%d ", ans); } return 0; }
D.最短路2
题意:在网格图上给两个点和一条直线 能从网格和直线上走 求最短路
题解:以两个点做出一个正方形 然后这条直线最多会和这个正方形有两个交点 以这些点建图跑最短路就好了
直线上两个点之间的距离是普通距离 其他则是曼哈顿距离
#include <bits/stdc++.h> #include <stdio.h> #include <iostream> using namespace std; double x1, yy, x2, y2, a, b, c; struct node { double x, y; int ty; }E[25]; struct no1 { int to; double val; }; vector<no1> g[35]; double dis[35]; int vis[25]; queue<int> que; void spfa() { for(int i = 1; i <= 10; i++) dis[i] = 1000000005; memset(vis, 0, sizeof(vis)); dis[1] = 0; vis[1] = 1; while(!que.empty()) que.pop(); que.push(1); while(!que.empty()) { int u = que.front(); que.pop(); vis[u] = 0; for(int i = 0; i < g[u].size(); i++) { if(dis[u] + g[u][i].val < dis[g[u][i].to]) { dis[g[u][i].to] = dis[u] + g[u][i].val; if(!vis[g[u][i].to]) { vis[g[u][i].to] = 1; que.push(g[u][i].to); } } } } } int main() { int T; scanf("%d", &T); while(T--) { for(int i = 1; i <= 20; i++) g[i].clear(); scanf("%lf %lf %lf %lf %lf %lf %lf", &x1, &yy, &x2, &y2, &a, &b, &c); double xx = min(x1, x2); double xd = max(x1, x2); double yx = min(yy, y2); double yd = max(yy, y2); E[1].x = x1; E[1].y = yy; E[1].ty = 0; E[2].x = x2; E[2].y = y2; E[2].ty = 0; E[3].x = x1; E[3].y = y2; E[3].ty = 0; E[4].x = x2; E[4].y = yy; E[4].ty = 0; int cnt = 4; if(fabs(a) > 1e-9) { double x3 = (c - b * yy) / a; if(x3 >= xx && x3 <= xd) { cnt++; E[cnt].x = x3; E[cnt].y = yy; E[cnt].ty = 1; } double x4 = (c - b * y2) / a; if(x4 >= xx && x4 <= xd) { cnt++; E[cnt].x = x4; E[cnt].y = y2; E[cnt].ty = 1; } } if(fabs(b) > 1e-9) { double y3 = (c - a * x1) / b; if(y3 >= yx && y3 <= yd) { cnt++; E[cnt].x = x1; E[cnt].y = y3; E[cnt].ty = 1; } double y4 = (c - a * x2) / b; if(y4 >= yx && y4 <= yd) { cnt++; E[cnt].x = x2; E[cnt].y = y4; E[cnt].ty = 1; } } for(int i = 1; i <= cnt; i++) { for(int j = 1; j <= cnt; j++) { if(i == j) continue; if(E[i].ty + E[j].ty < 2) { no1 p; p.to = j; p.val = fabs(E[i].x - E[j].x) + fabs(E[i].y - E[j].y); g[i].push_back(p); } else if(E[i].ty + E[j].ty == 2) { no1 p; p.to = j; p.val = sqrt((E[i].x - E[j].x) * (E[i].x - E[j].x) + (E[i].y - E[j].y) * (E[i].y - E[j].y)); g[i].push_back(p); } } } spfa(); printf("%.3lf ", dis[2]); } return 0; }
E.托米历险记 签到
#include <stdio.h> #include <algorithm> #include <iostream> using namespace std; int sum[5]; int main() { bool f = true; int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); x /= 25; if(x == 1) sum[1]++; else if(x == 2) { if(!sum[1]) f = false; sum[1]--; sum[2]++; } else if(x == 4) { if(sum[1] && sum[2]) { sum[1]--; sum[2]--; } else if(!sum[2]) { sum[1] -= 3; if(sum[1] < 0) f = false; } else if(!sum[1]) f = false; } } if(f) puts("YES"); else puts("NO"); return 0; }
F.填数字 随便贪心
#include <stdio.h> #include <algorithm> #include <iostream> using namespace std; int a[15]; int main() { int n; cin>>n; int zd = 10000000; int mark = -1; for(int i = 1; i <= 9; i++) { cin>>a[i]; if(a[i] <= zd) { zd = a[i]; mark = i; } } zd = n / a[mark]; if(zd == 0) puts("-1"); else { int x = zd * a[mark]; int res = n - x; int cnt = 0; for(int i = 9; i > mark; i--) { while(res >= a[i] - a[mark]) { res -= a[i] - a[mark]; cnt++; printf("%d", i); } } for(int i = cnt + 1; i <= zd; i++) printf("%d", mark); puts(""); } return 0; }