2017 JUST Programming Contest 2.0 题解
【题目链接】
首先,$n>m$或$k>m$或$k>n$就无解。
设$p = \frac{A}{B}$,$ans = C_{n - 1}^{k - 1}{\left( {\frac{A}{B}} \right)^{k}}{\left( {\frac{B-A}{B}} \right)^{n - k}} = \frac{{\left( {n - 1} \right)! \times {A^k} \times {{\left( {B - A} \right)}^{n - k}}}}{{\left( {k - 1} \right)! \times \left( {n - k} \right)! \times {B^n}}}$。令分子为$p$,分母为$q$,最终的答案为$p$*($q$的逆元)。
#include <bits/stdc++.h> using namespace std; const long long mod = 1e9 + 7; const int maxn = 2e5 + 10; long long f[maxn]; long long m, n, k; char s[maxn]; long long qpow(long long a, long long b) { long long res = 1LL; a = a % mod; while(b) { if(b & 1) res = (res * a) % mod; b = b / 2; a = (a * a) % mod; } return res; } long long extend_gcd(long long a,long long b,long long &x,long long &y) { if(a==0&&b==0) return -1;//无最大公约数 if(b==0){x=1;y=0;return a;} long long d=extend_gcd(b,a%b,y,x); y-=a/b*x; return d; } //*********求逆元素******************* //ax = 1(mod n) long long mod_reverse(long long a,long long n) { long long x,y; long long d=extend_gcd(a,n,x,y); if(d==1) return (x%n+n)%n; else return -1; } void init() { f[0] = 1LL; for(long long i = 1; i <= 100000; i ++) { f[i] = (f[i - 1] * i) % mod; } } int main() { init(); cin >> m >> n >> k >> s; if(n > m || k > m || k > n) { printf("0\n"); return 0; } if(s[0] == '1' && n == k) { printf("1\n"); return 0; } if(s[0] == '1') { printf("0\n"); return 0; } if(s[0] == '0' && s[2] == '0' && s[3] == '0' && s[4] == '0') { printf("0\n"); return 0; } long long A = 0; long long B = 1000LL; for(int i = 2; i <= 4; i ++) { A = A * 10LL + s[i] - '0'; } long long p, q; p = f[n - 1] * qpow(A, k) % mod; p = p * qpow(B - A, n - k) % mod; q = f[k - 1] * f[n - k] % mod; q = q * qpow(B, n) % mod; long long x = p * mod_reverse(q, mod) % mod; printf("%lld\n", x); return 0; }
B - So You Think You Can Count?
设$dp[i]$表示以$i$为结尾的方案数,每个位置最多往前扫$10$位。
#include <bits/stdc++.h> using namespace std; const long long mod = 1e9 + 7; const int maxn = 1e5 + 10; char s[maxn]; int n; long long dp[maxn]; long long DP(int x) { if(x < 0) return 1LL; return dp[x]; } int main() { scanf("%d", &n); scanf("%s", s); int len = strlen(s); dp[0] = 1LL; for(int i = 1; i < len; i ++) { int tmp[20]; for(int j = 0; j <= 9; j ++) { tmp[j] = 0; } for(int pre = i; pre >= 0; pre --) { if(tmp[s[pre] - '0']) break; tmp[s[pre] - '0'] = 1; dp[i] = (dp[i] + DP(pre - 1)) % mod; } } printf("%lld\n", dp[len - 1]); return 0; }
最短路,数据有点水,没把spfa卡住。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; int S, T, n, m; char name[maxn][25]; int h[maxn], nx[maxn], to[maxn], c[maxn], sz; int t1[30], t2[30]; int cost(int x, int y) { memset(t1, 0, sizeof t1); memset(t2, 0, sizeof t2); for(int i = 0; name[x][i]; i ++){ if(name[x][i] >= 'a' && name[x][i] <= 'z') { t1[name[x][i] - 'a'] ++; } if(name[x][i] >= 'A' && name[x][i] <= 'Z') { t1[name[x][i] - 'A'] ++; } } for(int i = 0; name[y][i]; i ++){ if(name[y][i] >= 'a' && name[y][i] <= 'z') { t2[name[y][i] - 'a'] ++; } if(name[y][i] >= 'A' && name[y][i] <= 'Z') { t2[name[y][i] - 'A'] ++; } } int num = 0; for(int i = 0; i < 26; i ++) { if(t1[i] && t2[i]) num ++; } return num; } void add(int x, int y, int z) { to[sz] = y; c[sz] = z; nx[sz] = h[x]; h[x] = sz++; } int dis[maxn], f[maxn]; void spfa() { for(int i = 1 ;i <= n; i ++) { f[i] = 0; dis[i] = 0x7FFFFFFF; } queue<int> Q; Q.push(S); f[S] = 1; dis[S] = 0; while(!Q.empty()) { int top = Q.front(); Q.pop(); f[top] = 0; for(int i = h[top]; i != -1; i = nx[i]) { if(dis[top] + c[i] < dis[to[i]]) { dis[to[i]] = dis[top] + c[i]; if(f[to[i]] == 0) { f[to[i]] = 1; Q.push(to[i]); } } } } } int main() { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i ++) { scanf("%s", name[i]); h[i] = -1; } for(int i = 1; i <= m; i ++) { int u, v; scanf("%d%d", &u, &v); add(u, v, cost(u, v)); add(v, u, cost(u, v)); } scanf("%d%d", &S, &T); spfa(); printf("%d\n", dis[T]); return 0; }
模拟。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 10; char s[maxn]; int main() { int T; scanf("%d", &T); while(T --) { scanf("%s", s); int num1=0, num2=0, num3=0; for(int i = 0; s[i];i ++) { if(s[i]>='a'&&s[i]<='z') num1++; else if(s[i]>='A'&&s[i]<='Z') num1++; else if(s[i]>='0'&&s[i]<='9') num2++; else if(s[i] =='!' || s[i] =='?'||s[i] == '@') { num3++; } } if(num1 < 4) { printf("The last character must be a letter.\n"); continue; } if(num2 < 4) { printf("The last character must be a digit.\n"); continue; } if(num3 < 2) { printf("The last character must be a symbol.\n"); continue; } printf("The last character can be any type.\n"); } return 0; }
由于验证的复杂度只有$O(26)$,因此可以枚举答案。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; int n, m; char s[maxn]; long long f[maxn]; int main() { scanf("%s", s); for(int i = 0; s[i]; i ++) { f[s[i] - 'a'] ++; } long long ans = -1; long long mn = -1; for(long long i = 2; i <= 300000; i ++) { long long tmp = 0; for(int j = 0; j < 26; j ++) { tmp = tmp + (f[j] % i) * f[j]; } if(mn == -1 || tmp < mn) { mn = tmp; ans = i; } } printf("%lld\n", ans); return 0; }
二分查找。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; int n, m; int a[maxn]; int main() { scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d", &a[i]); sort(a + 1, a + 1 + n); scanf("%d", &m); while(m --) { int x; scanf("%d", &x); int L = 1, R = n, pos = -1; while(L <= R) { int mid = (L + R) / 2; if(a[mid] >= x) pos = mid, R = mid - 1; else L = mid + 1; } if(pos == -1) printf("Dr. Samer cannot take any offer :(.\n"); else printf("%d\n", a[pos]); } return 0; }
模拟。
#include <bits/stdc++.h> using namespace std; int main() { int n, m; cin>> n>>m; if(m % n == 0) printf("YES\n"); else printf("NO\n"); return 0; }
这题为单调栈经典问题,但是由于数值范围只有$50$,因此可以枚举数值。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; int n, m; int a[maxn]; int b[maxn]; int num[maxn]; int main() { scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%d", &a[i]); } for(int i = 0; i<= 100; i ++) num[i] = 200000; for(int j = n; j>=1; j--) { b[j] = 200000; for(int k = 50; k >= a[j] + 1; k--){ if(num[k] < b[j]) b[j] = num[k]; } num[a[j]] = j; if(b[j] != 200000) b[j] = a[b[j]]; else b[j] = -1; } for(int i =1 ;i <= n; i ++) { printf("%d ", b[i]); } return 0; }
I - Husam and the Broken Present 1
对主对角线开根号来求解。
#include <bits/stdc++.h> using namespace std; int main() { int n; cin>> n; int x; for(int i = 1; i <= n; i ++) { for(int j = 1; j <= n; j++){ cin>>x; if(i == j){ int num = sqrt(1.0 * x); while(num * num > x) num--; while(num*num<x)num++; printf("%d ", num); } } } return 0; }
J - Husam and the Broken Present 2
先删除被包含的那些数组,剩下的可以进行状压$dp$来决策放置顺序。$dp[st][v]$表示有$st$状态里面的子数组已经放置好了,最后放的是$v$的最小花费,和TSP是一样的问题。
#include <bits/stdc++.h> using namespace std; const int maxn = 1000; vector<int> vec[maxn], t[maxn]; int cost[20][20]; int n; int dp[70000][17]; int han(vector<int>& a, vector<int>& b) { // a 是否在 b 中 if(b.size() < a.size()) return 0; for(int i = 0; i < b.size(); i ++) { int L = i, R = i + a.size() - 1; if(R >= b.size()) break; int fail = 0; for(int j = 0; j < a.size(); j ++) { if(a[j] != b[L + j]) fail = 1; } if(fail == 0) return 1; } return 0; } int cal(int x, int y) { // x 后面 接 y int res = 0; for(int i = 0; i < t[x].size(); i ++) { if(t[x].size() - i > t[y].size()) continue; int fail = 0; for(int j = i; j < t[x].size(); j ++) { if(t[x][j] != t[y][j - i]) fail = 1; } //printf("!!! %d, %d\n", i, fail); if(fail == 0) { res = t[x].size() - i; break; } } return t[y].size() - res; } bool cmp(const vector<int> &a, const vector<int> &b) { return a.size() > b.size(); } int main() { scanf("%d", &n); for(int i = 0; i < n; i ++) { int x; scanf("%d", &x); while(x--){ int p; scanf("%d", &p); vec[i].push_back(p); } } sort(vec, vec + n, cmp); int sz = 0; t[sz++] = vec[0]; for(int i = 1; i < n; i ++) { int fail = 0; for(int j = 0; j < sz; j ++) { if(han(vec[i], t[j])) { fail = 1; break; } } if(fail) continue; t[sz ++] = vec[i]; } n = sz; /* for(int i = 0; i < n; i ++) { for(int j = 0; j < t[i].size(); j ++) { cout << t[i][j] << " "; } cout << endl; } */ for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(i == j) continue; cost[i][j] = cal(i, j); } } for(int st = 0; st < (1 << n); st ++) { for(int i = 0; i < n; i ++) { dp[st][i] = 200000; } } for(int i = 0; i < n; i ++) { dp[1 << i][i] = t[i].size(); } for(int st = 1; st < (1 << n); st ++) { for(int pre = 0; pre < n; pre ++) { if(((1 << pre) & st) == 0) continue; for(int now = 0; now < n; now ++) { if((1 << now) & st) continue; dp[st | (1 << now)][now] = min(dp[st | (1 << now)][now], dp[st][pre] + cost[pre][now]); } } } int ans = dp[(1 << n) - 1][0]; for(int i = 0; i < n; i ++) { ans = min(ans, dp[(1 << n) - 1][i]); } printf("%d\n", ans); return 0; } /* 3 2 1 2 4 3 4 5 6 3 2 3 4 */