<牛客練習賽20>
阿新 • • 發佈:2018-06-17
最短 sca pre view while else lse include return
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; forView Code(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\n", 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\n", ans); } return 0; }View Code
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\n", ans); } return 0; }View Code
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\n", dis[2]); } return 0; }View Code
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; }View Code
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; }View Code
<牛客練習賽20>