A. Assignments
水题,随便写。
二分油箱容积,判断是否符合。判断可行性时预处理各点两两间是否能一次走完,能的话在这两点间构建边权为1的边,完了后跑最短路得到最大加油次数,与k比较即可。
代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int maxn = 100 + 5; 7 typedef long long ll; 8 const ll inf = 0x3f3f3f3f; 9 10 ll mp[maxn][maxn]; 11 int dp[maxn][maxn]; 12 int n, m, K; 13 14 void ini() { 15 for(int k=0;k<n;k++) { 16 for(int i=0;i<n;i++) { 17 mp[i][i] = 0; 18 for(int j=0;j<n;j++) { 19 if(i==k || mp[i][k]==inf || mp[k][j]==inf) continue; 20 mp[i][j] = min(mp[i][j], mp[i][k]+mp[k][j]); 21 } 22 } 23 } 24 } 25 26 bool solve(ll x) { 27 for(int i=0;i<n;i++) { 28 for(int j=0;j<n;j++) 29 dp[i][j] = mp[i][j]<=x?1:inf; 30 } 31 for(int k=0;k<n;k++) { 32 for(int i=0;i<n;i++) { 33 dp[i][i] = 0; 34 for(int j=0;j<n;j++) { 35 if(i==k || dp[i][k]==inf||dp[k][j]==inf) continue; 36 dp[i][j] = min(dp[i][j], dp[i][k]+dp[k][j]); 37 } 38 } 39 } 40 for(int i=0;i<n;i++) { 41 for(int j=0;j<n;j++) if(dp[i][j]>K) return 0; 42 } 43 return 1; 44 } 45 46 int main() { 47 int T; 48 scanf("%d", &T); 49 while(T--) { 50 int x, y; 51 ll w, l=0, r=0; 52 scanf("%d%d%d", &n, &K, &m); 53 memset(mp, 0x3f, sizeof(mp)); 54 for(int i=0;i<m;i++) { 55 scanf("%d%d%lld", &x, &y, &w); 56 mp[x][y] = mp[y][x] = w; 57 r+=w; 58 } 59 ini(); 60 while(l<r) { 61 ll mid = l+r>>1; 62 if(solve(mid)) r=mid; 63 else l=mid+1; 64 } 65 printf("%lld\n", l); 66 } 67 }
概率顺着走,概数倒着走,用dp[si]表示由si状态达到最终状态的平均步数,我们可以得到2个方程式:
第一种情况:
第二钟情况:
其中sj表示si能达到的状态,cnt表示共有多少个状态可达。
代码:
1 #include<cstring> 2 #include<cstdio> 3 #include<algorithm> 4 #include<unordered_map> 5 #include<iostream> 6 using namespace std; 7 const int maxn = 15; 8 typedef double intd; 9 10 int a[maxn], b[maxn]; 11 unordered_map<int,intd> dp[2]; 12 13 int n, ed; 14 15 int Hash(int *arry) { 16 int rtn = 0; 17 for(int i=0;i<n;i++) 18 rtn = rtn*8 + arry[i]; 19 return rtn; 20 } 21 22 intd Dp1() { 23 int sta = Hash(a); 24 if(sta == ed) return 0.0; 25 if(dp[0].count(sta)) return dp[0][sta]; 26 intd sum = 0.0; 27 int cnt = 0; 28 for(int i=0;i<n;i++) { 29 for(int j=0;j<n;j++) if(a[min(i,j)]>a[max(i,j)]){ 30 cnt ++; 31 swap(a[i], a[j]); 32 sum += Dp1(); 33 swap(a[i], a[j]); 34 } 35 } 36 return dp[0][sta] = sum/(1.0*cnt) + n*n*1.0/(1.0*cnt); 37 } 38 39 intd Dp2() { 40 int sta = Hash(a); 41 if(sta == ed) return 0.0; 42 if(dp[1].count(sta)) return dp[1][sta]; 43 intd sum = 0.0; 44 int cnt = 0; 45 for(int i=0;i<n-1;i++) if(a[i]>a[i+1]){ 46 cnt ++; 47 swap(a[i], a[i+1]); 48 sum += Dp2(); 49 swap(a[i], a[i+1]); 50 } 51 return dp[1][sta] = sum/(1.0*cnt) + (n-1)*1.0/(1.0*cnt); 52 } 53 54 int main() { 55 int T; 56 scanf("%d", &T); 57 while(T--) { 58 scanf("%d", &n); 59 for(int i=0;i<n;i++) { 60 scanf("%d", a+i); 61 b[i] = a[i]; 62 } 63 sort(b, b+n); 64 for(int i=0;i<n;i++) { 65 int rk=lower_bound(b,b+n,a[i])-b; 66 a[i] = rk; 67 } 68 for(int i=0;i<n;i++) 69 b[i] = a[i]; 70 sort(b, b+n); 71 int be = Hash(a); 72 ed = Hash(b); 73 dp[0].clear(); 74 dp[1].clear(); 75 Dp1(); 76 Dp2(); 77 printf("Monty %.6f Carlos %.6f\n", dp[0][be], dp[1][be]); 78 } 79 return 0; 80 }
转换一下题意就知道这个题就是给定一棵树,删去k条边,保证其联通,求最小权值和,输出时乘上2即可。
随便取个点当作根节点,用dp[i][j]表示以节点i为根节点的字树中删去j条路径的最大权值,dfs遍历每个节点即可。
注意根节点可能会被删除,所以遍历时加个判断,如果某棵子树的节点树就为N-k就用它的权值和跟新答案。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int maxn = 1e4 + 5; 8 const int maxm = 20 + 5; 9 const ll inf = 0x3f3f3f3f3f3f; 10 11 struct Node 12 { 13 int v, u, to; 14 ll w; 15 }p[maxn<<1]; 16 int h[maxn]; 17 int tot; 18 ll dp[maxn][maxm]; 19 int N, k; 20 ll sum, ans; 21 22 void ini() 23 { 24 tot = 0; 25 sum = 0; 26 memset(h, -1, sizeof(h)); 27 memset(dp, 0, sizeof(dp)); 28 } 29 30 void add(int v,int u,ll w) 31 { 32 p[tot].v = v; 33 p[tot].u = u; 34 p[tot].w = w; 35 p[tot].to = h[v]; 36 h[v] = tot++; 37 } 38 39 void dfs(int v,int fa,int& cnt,ll& sw) 40 { 41 cnt = 1; 42 sw = 0; 43 for(int t=h[v];~t;t=p[t].to) { 44 int u = p[t].u; 45 if(u == fa) continue; 46 int cn; 47 ll sn; 48 dfs(u, v, cn, sn); 49 if(cn == N-k) 50 ans = min(ans, sn*2); 51 52 if(cn <= k) 53 dp[u][cn] = dp[u][cn-1]+p[t].w; 54 sw += p[t].w + sn; 55 cnt += cn; 56 for(int i=k;i>=0;i--) { 57 ll maxs = 0; 58 for(int j=0;j<=i;j++) 59 maxs = max(maxs, dp[v][j]+dp[u][i-j]); 60 dp[v][i] = maxs; 61 } 62 } 63 } 64 65 int main() 66 { 67 int T; 68 scanf("%d", &T); 69 while(T--) { 70 ini(); 71 scanf("%d%d", &N, &k); 72 for(int i=0;i<N-1;i++) { 73 int v, u; 74 ll w; 75 scanf("%d%d%lld", &v, &u, &w); 76 add(v, u, w); 77 add(u, v, w); 78 sum += w; 79 } 80 int cnt; 81 ll sn; 82 ans = inf; 83 dfs(0, 0, cnt, sn); 84 if(cnt==N-k) { 85 printf("%lld\n", sum*2); 86 continue; 87 } 88 for(int i=0;i<N;i++) 89 ans = min(ans, 2*sum-2*dp[i][k]); 90 printf("%lld\n", ans); 91 } 92 return 0; 93 }
水题,优先队列一下就行。
水水水,暴力即可。
H2O,直接写。
可将X分解为:
那么Y可表示为:
我们可以知道 a[i] < 10,而Y的个位与a[i]+a[k-i]的个位是一定相同的,我们枚举a[i]+a[k-i]的大小(最多两种),减去第i项与k-i项,可以发现变成了一个类似的子问题,dfs即可,注意高位不能有前导0.
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 20; ll pows[maxn]; void ini() { pows[0] = 1; for(int i=1;i<maxn;i++) pows[i] = pows[i-1]*10; } ll dfs(ll n,int len,int flag) { if(n == 0) return 1; if(n < 0) return 0; if(len == 0) return 0; if(len == 1) { if(n < 20 && (n & 1)==0) return 1; return 0; } ll rtn = 0; ll x = n%10; rtn += dfs((n-x*(1+pows[len-1]))/10, len-2, 0)*(x+1-flag); rtn += dfs((n-(10+x)*(1+pows[len-1]))/10, len-2, 0)*(9-x); return rtn; } int main() { int T; ll n; ini(); scanf("%d", &T); while(T--) { scanf("%lld", &n); int len = 0; ll m = n; while(m) len++, m/=10; ll ans = 0; for(int i=len;i>=1;i--) ans += dfs(n, i, 1); printf("%lld\n", ans); } }
想法题,想到了这个题就贼水了。
引入虫洞相当于把整个宇宙分为了两大块,使得两个宇宙间星球距离减小,但每个宇宙间的星球就没有受惠。这个题相当于把每个宇宙分为两部分,使得每部分星球最大距离最小。
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 4000 + 5; int a[maxn]; int main() { int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i=0;i<n;i++) scanf("%d", a+i); sort(a, a+n); int ans = 0; for(int i=0;i<n;i++) ans = max(ans, min(a[i]-a[0], a[n-1]-a[i])); printf("%d\n", ans); } return 0; }
挖坑。
挖坑。
L. Languages
水题,暴力匹配。
待补。