组队赛5 - 2014.8.10
来源:互联网 发布:软件质量保证的过程 编辑:程序博客网 时间:2024/05/22 17:39
http://vjudge.net/contest/view.action?cid=53221#overview
UVALive 6434 - Number Assignment
problem
给你n个数,分为m组。每组的最大值减去最小值的差值加起来,最小是多少。
think
排序后。有n-1个差值。
答案就是这n-1的差值和(也是这n个数的最大值减最小值),减去m-1个最大的差值。
UVALive 6435 - Network Packet Ordering
problem
给你n,m,d,n个数表示A里面n个人到达的时间,m个数表示B里面m个人到达的时间。
如A里面第i个人的时间是ai,则他在 [ai, ai + d) 的时间到达。同理bi 。
A、B里面的人给的时间都是从小到大的,ai < a(i+1) , 同理bi 。
在一个序列里面的人是依次到达,不能交换顺序。如d = 2. ai = 1, a(i+1) = 2, 也必须i在i+1前面。同理B.
AB没有顺序关系。问有多少种顺序。
think
A把时间分为n+1个区间。
由于a<a(i+1),d<=100, 所以每个bi最多在200个区间。
dp[i][j]表示bi在它可以在的第j个区间。
转移就是:
jjj = min(R[i-1], jj) - L[i-1];
dp[i][j] = sum[i-1][jjj];
其中jj表示j表示的那个区间。R[i]表示i可以在的最后那个区间,sum[i][j] = sum(dp[i][k], k <= j)
code
const int N = 50010;const int mod = 1000000009;int a[N], b[N];int L[N], R[N];int dp[N][300];int sum[N][300];int main(){ int T, tt = 0; scanf("%d", &T); while(T--){ int n, m, d; scanf("%d%d%d", &n, &m, &d); for(int i = 0; i < n; ++i) scanf("%d", &a[i]); for(int j = 0; j < m; ++j) scanf("%d", &b[j]); for(int j = 0; j < m; ++j){ int i = 0; if(j > 0) i = L[j-1]; L[j] = -1; R[j] = -1; for(; i < n; ++i){ if(b[j] >= a[i] + d) continue; if(i > 0 && b[j] + d <= a[i-1]) break; if(L[j] == -1) L[j] = i; R[j] = i; } if(L[j] == -1) L[j] = n; if(R[j] == -1 || b[j] + d > a[n-1]) R[j] = n; } for(int i = 0; i < m; ++i){ for(int j = 0, jj = L[i]; jj <= R[i]; ++j, ++jj){ if(i == 0){ dp[i][j] = 1; continue; } int jjj = min(R[i-1], jj) - L[i-1]; dp[i][j] = sum[i-1][jjj]; } sum[i][0] = dp[i][0]; for(int j = 1, jj = L[i] + 1; jj <= R[i]; ++j, ++jj){ sum[i][j] = sum[i][j-1] + dp[i][j]; if(sum[i][j] >= mod) sum[i][j] -= mod; } } printf("Case #%d: %d\n", ++tt, sum[m-1][R[m-1]-L[m-1]]); } return 0;}
UVALive 6436 - The Busiest City
problem
一棵树。每个点的值是这个数的任两个点path经过这个点(并且这个点不是端点)的个数。
think
设s为这个点。sz[s]表示s的子树大小。ss是s的孩子。
那么 val[s] = sum(sz[ss] * (n - 1 - sz[ss]) + (n - sz[s]) * (sz[s] - 1));
code
vector<int>v[20010];int sz[20010];int ans, n;void dfs(int s, int pre){ int len = v[s].size(); sz[s] = 1; int res = 0; for(int i = 0; i < len; ++i){ int ss = v[s][i]; if(ss == pre) continue; dfs(ss, s); res += sz[ss] * (n - 1 - sz[ss]); sz[s] += sz[ss]; } res += (n - sz[s]) * (sz[s] - 1); if(res > ans) ans = res;}int main(){ int T, tt = 0; scanf("%d", &T); while(T--){ scanf("%d", &n); for(int i = 1; i < n; i++){ int a, b; scanf("%d%d", &a, &b); v[a].PB(b); v[b].PB(a); } ans = 0; dfs(1, 0); printf("Case #%d: %d\n", ++tt, ans>>1); for(int i = 1; i <= n; ++i) v[i].clear(); } return 0;}
UVALive 6439 - Pasti Pas!
problem
给你一个串,可以把某些字符变成一个字符,如ABCDAB可以把AB变成a,把CD变成b,这样就变成了aba。
变完一定得是回文串。
问变完最长是多长。
think
从两头找。
如果两头找到已经可以变成一样的,那么他俩一定匹配。如AB……AB,那么AB一定变成一个字符。
因为如果他俩不变的话,也一定是AB*AB 和AB*AB为了是他俩一样。
根据这个性质,就从两边找吧。而且左边的指针i和j的话,j一直往后,找到可以的j,i和j都变成j+1,所以复杂度就是串长。
然后判断的时候hash。就可以O(1)判断了。
UVALive 6440 - Emergency Handling
problem
有n个操作。P表示进来一个病人,t0,s0,r,表示在t0时刻进来,他的危险值是s0 + r * (t - t0),t 是 >= t0的时刻。
A表示t0时刻可以抢救一个人。抢救那个危险值最大的。如果危险值一样就抢救r最大的。输出抢救的人的危险值和r。
think
r是[0, 100],所以建立101个优先队列。
把病人的危险值变为s0 - r*t0 + r*t, 优先队列里面放的是s0 - r*t0.
这样进去病人的时候,复杂度是log
抢救的时候要遍历101个队列,top操作是O(1),复杂度是101.
所以总的复杂度是T * n * max(logn, 101).
code
int main(){ int t, tt = 0; scanf("%d",&t); while(t--){ printf("Case #%d:\n", ++tt); priority_queue<int,vector<int>,less<int> >q[101]; int n; scanf("%d",&n); while(n--){ char str[5]; int t0,s0,r,s; scanf("%s%d", str, &t0); if(str[0] == 'A'){ r = 0; LL sc = 0; for(int i = 0; i <= 100; ++i) if(!q[i].empty()){ s = q[i].top(); LL tmp = (LL)s + i * t0; if(tmp >= sc){ r = i; sc = tmp; } } q[r].pop(); printf("%lld %d\n", sc, r); } else { scanf("%d%d", &s0, &r); q[r].push(s0 - r*t0); } } } return 0;}
UVALive 6441 - Horrible Quiz
problem
一个人的开始分数是15000.做n道题。他自己做对的概率是w/100, 做错的概率是c/100,使用你给的答案的概率是1 - w/100 - c/100。
你要给他n个答案,最多给m个错误答案。
作对了就乘以1,做错了就乘以-1.
求他的最低分数的期望。
think
dp[i][j][2], 分别表示到第i道题已经给了j个错误答案的期望的最大值和最小值。
做对的话就是乘以 ww = (100 - 2 * c[i+1]) / 100.; 做错就是乘以 cc = (2 * w[i+1] - 100) / 100.;
code
int w[N], c[N];double f[N][N][2];int n, m;int main(){ int T, tt = 0; scanf("%d", &T); while(T--){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) scanf("%d", &w[i]); for(int i = 1; i <= n; ++i) scanf("%d", &c[i]); for(int i = 0; i <= n; ++i) for(int j = 0; j <= m; ++j){ f[i][j][0] = 15000; f[i][j][1] = -15000; } f[0][0][0] = 15000; f[0][0][1] = 15000; for(int i = 0; i < n; ++i){ for(int j = 0; j <= i && j <= m; ++j){ double ww = (100 - 2 * c[i+1]) / 100.; double cc = (2 * w[i+1] - 100) / 100.; f[i+1][j][0] = min(f[i+1][j][0], f[i][j][0] * ww); f[i+1][j][0] = min(f[i+1][j][0], f[i][j][1] * ww); f[i+1][j][1] = max(f[i+1][j][1], f[i][j][0] * ww); f[i+1][j][1] = max(f[i+1][j][1], f[i][j][1] * ww); f[i+1][j+1][0] = min(f[i+1][j+1][0], f[i][j][0] * cc); f[i+1][j+1][0] = min(f[i+1][j+1][0], f[i][j][1] * cc); f[i+1][j+1][1] = max(f[i+1][j+1][1], f[i][j][0] * cc); f[i+1][j+1][1] = max(f[i+1][j+1][1], f[i][j][1] * cc); } } double ans = 15000; for(int j = 0; j <= m; ++j) ans = min(ans, f[n][j][0]); printf("Case #%d: %.3f\n", ++tt, ans); } return 0;}
UVALive 6442 - Coins on a Ring
problem
一个环,n个位置,有m个人,m被n整除。现在要把m个人移动位置使他们的间距相同。
消耗的能量是移动的最多的那个人的移动了多少。
求最少消耗的能量。
think
排序后让他们依次对应某个可以的序列,如0, n/m, 2*n/m ……
然后依次得到差值,最大差值和最小差值的中间的数就是答案。。
code
int a[20100];int main(){ int T, tt = 0; scanf("%d", &T); while(T--){ int n, m, k; scanf("%d%d", &n, &m); k = n / m; int mi = n; int mx = -n; for(int i = 0; i < m; ++i) scanf("%d", &a[i]); sort(a, a + m); for(int i = 0; i < m; ++i){ int pos = k * i - a[i]; mi = min(mi, pos); mx = max(mx, pos); } printf("Case #%d: %d\n", ++tt, (mx - mi + 1) / 2); } return 0;}
- 组队赛5 - 2014.8.10
- 省赛组队赛5
- 13/9/5 组队赛
- 组队赛5:二分图+大模拟
- 7 28 组队赛
- 组队赛130827
- 组队赛130926
- 国庆组队赛131002
- 组队_浙江省赛
- CUGBACM_组队赛1
- 组队赛 五
- 4.19新生组队赛
- 一次组队赛总结
- 8.26组队赛
- 组队赛整理
- 组队赛感悟
- 组队
- 组队赛4 - 2014.8.3 - 2013成都现场赛
- ViewFlipper
- 关于httpclient 请求https (如何绕过证书验证)
- android:点击左边按钮增加数值,点击右边按钮减小数值
- 代码坏味道之夸夸其谈的未来性
- Failure [INSTALL_FAILED_OLDER_SDK] Android-L
- 组队赛5 - 2014.8.10
- MVN 添加本地Jar
- UVA165
- java中关于Map的九大问题
- zoj 2788 Panic Room (最小割)
- 《一步一脚印 90后程序员》16
- 一分钟经理答案
- 工作问题之自定义confirm功能框
- 以太网,局域网,万维网