组队赛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;}


0 0
原创粉丝点击