组队赛3 - 2014.7.27 - 2013长沙现场赛

zoj-3734-LIKE vs CANDLE

problem

打印。有n种收费方式。打印的纸是ai<=x<a(i+1),就是pi钱一张。ai<=a(i+1), pi>=p(i+1)

问打印y张最少多少钱,有m个询问。

think

对于y张纸,找到他在的区间ai<=y<a(i+1),答案就是min(y*pi, aj*pj), j>i

code

const int N = 111111;

LL a[N], b[N], c[N], d[N];
struct point{
    LL a;
    int id;
}p[N];
LL ans[N];

bool cmp(point x, point y){
    return x.a < y.a;
}

int main(){
    int T, tt = 0;
    int n, m;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; ++i) scanf("%lld%lld", &a[i], &b[i]);
        for(int i = n - 1; i >= 0; --i){
            c[i] = a[i]*b[i];
            if(i == n-1 || c[i] < d[i+1]) d[i] = c[i];
            else d[i] = d[i+1];
        }
        for(int i = 0; i < m; ++i) {
            scanf("%lld", &p[i].a);
            p[i].id = i;
        }
        sort(p, p + m, cmp);
        for(int i = 0, j = 0; i < m; ++i){
            while(j < n-1 && a[j+1] <= p[i].a) ++j;
            if(j == n-1 || p[i].a * b[j] < d[j+1]) ans[p[i].id] = p[i].a * b[j];
            else ans[p[i].id] = d[j+1];
        }
        for(int i = 0; i < m; ++i) printf("%lld\n", ans[i]);
    }
    return 0;
}

zoj-3732-Graph Reconstruction

problem

给你n[2, 100]个点的度,问是否能构造出一个无向图(没有自环和重边)。

没有就输出没有。有唯一的图就输出这个图。有两个或以上的图就输出其中两个。

think

每次都按度排序。用最大的度依次和第二大第三大……的度(他们的度分别减掉1)匹配。知道完全满足最大的度。

这样出现负数的度数就是没解了。

这样当匹配到第i个点,i+du的点和i+du+1的点(按照从大到小排序后的序号)度数一样,那么这时i选择和i+du的点和i+du+1的点之一哪个都行,就出现了多解。

code

const int N = 111;

struct point{
    int id;
    int du;
    int oig;
}p[N];

int a[N*N], b[N*N];
int cnt, C, n, X, Y;

bool cmp(point x, point y){
    return x.du > y.du;
}

bool meng(){
    cnt = 0;
    X = -1;
    for(int i = 0; i < n; ++i){
        sort(p + i, p + n, cmp);
        if(p[n-1].du < 0) return false;
        if(p[i].du >= n - i) return false;
        if(p[i].du == 0) return true;
        if(p[i].du <= n - i - 2){
            int id1 = p[i].du + i;
            int id2 = p[i].du + i + 1;
            if(X == -1 && p[id1].du == p[id2].du){
                X = p[id1].id;
                Y = p[id2].id;
                C = cnt;
            }
        }
        for(int j = 1; j <= p[i].du; ++j){
            --p[i+j].du;
            a[cnt] = p[i].id;
            b[cnt++] = p[i+j].id;
        }
    }
    return true;
}

int main(){
    int T, tt = 0;
    while(scanf("%d", &n) != EOF){
        for(int i = 0; i < n; ++i){
            scanf("%d", &p[i].oig);
            p[i].du = p[i].oig;
            p[i].id = i + 1;
        }
        if(meng()){
            if(X == -1){
                puts("UNIQUE");
                printf("%d %d\n", n, cnt);
                for(int i = 0; i < cnt; ++i) {
                    printf("%d", a[i]);
                    if(i < cnt - 1) putchar(' ');
                }
                puts("");
                for(int i = 0; i < cnt; ++i) {
                    printf("%d", b[i]);
                    if(i < cnt - 1) putchar(' ');
                }
                puts("");

            } else {
                puts("MULTIPLE");
                printf("%d %d\n", n, cnt);
                for(int i = 0; i < cnt; ++i) {
                    printf("%d", a[i]);
                    if(i < cnt - 1) putchar(' ');
                }
                puts("");
                for(int i = 0; i < cnt; ++i) {
                    printf("%d", b[i]);
                    if(i < cnt - 1) putchar(' ');
                }
                puts("");
                printf("%d %d\n", n, cnt);
                for(int i = 0; i < cnt; ++i) {
                    if(a[i] == X && i >= C) printf("%d", Y);
                    else if(a[i] == Y && i >= C) printf("%d", X);
                    else printf("%d", a[i]);
                    if(i < cnt - 1) putchar(' ');
                }
                puts("");
                for(int i = 0; i < cnt; ++i) {
                    if(b[i] == X && i >= C) printf("%d", Y);
                    else if(b[i] == Y && i >= C) printf("%d", X);
                    else printf("%d", b[i]);
                    if(i < cnt - 1) putchar(' ');
                }
                puts("");
            }
        } else {
            puts("IMPOSSIBLE");
        }
    }
    return 0;
}


zoj-3733-Skycity

problem

R,r,H, F, S

表示给你一个圆锥去掉尖儿。上面半径r,下面半径R,一共高H,等高的分成F份。

每份装矩形玻璃。每块玻璃不能面积小于S。求最小玻璃面积。

think

tan(pi/n) * RR * 2 * h >= S 得到最大可以装几边形。

code

const double pi = acos(-1.);

int main(){
    int T, tt = 0;
    double R, r, H, S;
    int F;
    while(cin >> R >> r >> H >> F >> S){
        double ans = 0;
        double rr = (R - r) / F;
        double h = H / F;
        R = r;
        for(int i = 0; i < F; ++i){
            //根据tan(pi/n) * RR * 2 * h >= S 得:
            int n = pi / atan(S/2/R/h);
            ans += tan(pi/n) * R * 2 * n;
            R += rr;
        }
        printf("%.3f\n", ans * h);
    }
    return 0;
}


zoj-3734-LIKE vs CANDLE

problem

一棵树。有三个值,第一个值是权值,第二个值是0或1表示他是否被翻转过,第三个值是0或1表示他是哪边的。

对于每棵子树,可以翻转他,改变这棵子树的每个第三个值,如果他没被翻转过代价是X,否则是Y。

0是根节点,不能翻转。

求最大的第三个值是0的的第一个值的和,减去第三个值是1的的第一个值的和。的差的最大值。

think

树形DP。

dp[i][j]k],i表示i节点,j[0|1]表示是否没翻转过,k[0|1]表示他是否被改变,即被翻转过奇数还是偶数次。

code

const int N = 55555;
const int INF = 1000000000;

vector<int>v[N];
int a[N];
int s[N];
int p[N];
int dp[N][2][2];
int n, X, Y;

int dfs(int x, int sf, int ss){
    if(dp[x][sf][ss] != -INF) return dp[x][sf][ss];
    int ans = (sf^ss^p[x]) ? -a[x] : a[x];
    if(ss != s[x]) ans -= s[x] ? Y : X;
    int len = v[x].size();
    for(int i = 0; i < len; ++i){
        int y = v[x][i];
        ans += max(dfs(y, sf^ss, 0), dfs(y, sf^ss, 1));
    }
    return dp[x][sf][ss] = ans;
}

int main() {
    while(scanf("%d%d%d", &n, &X, &Y) != EOF){
        int x = 1, y;
        for(int i = 1; i <= n; ++i){
            scanf("%d%d%d%d", &a[i], &y, &s[i], &p[i]);
            if(y==0) x = i;
            else v[y].push_back(i);
        }
        for(int i = 1; i <= n; ++i){
            for(int j = 0; j <= 1; ++j){
                for(int k = 0; k <= 1; ++k){
                    dp[i][j][k] = -INF;
                }
            }
        }
        int ans = max(dfs(x, 0, 0), dfs(x, 0, 1));
        if(ans < 0) puts("HAHAHAOMG");
        else printf("%d\n", ans);
        for(int i = 0; i <= n; ++i) v[i].clear();
    }
    return 0;
}


zoj-3735 -Josephina and RPG

problem

有C(m, 3)种队伍,已知第i种队伍打败第j种队伍的概率。告诉你对方一次派出哪种队伍。求你每次都打败对方的最大概率。

第一次选择你可以选择任意一支队伍。第i(i>1)次选择,你可以选择第i-1次你使用的队伍,或者第i-1次对方使用的队伍。

think

dp[i][j] 表示第i次应战,使用j队伍赢的最大概率。

dp[i-1][j]*a[j][id[i]] ->      dp[i][j]
dp[i-1][j]*a[id[i-1]][id[i]] ->      dp[i][id[i-1]]

code

const int maxn = 10010;
double dp[maxn][200];
double a[200][200];
int id[maxn];

int main () {
    int m, n;
    while(scanf("%d", &m)!=EOF){
        m = m * (m-1) * (m-2) / 6;
        for(int i = 0; i < m; ++i) for(int j = 0; j < m; ++j) scanf("%lf", &a[i][j]);
        scanf("%d", &n);
        scanf("%d", &id[0]);
        memset(dp, 0, sizeof(dp));
        for(int j = 0; j < m; ++j){
            dp[0][j] = a[j][id[0]];
        }
        for(int i = 1; i < n; ++i){
            scanf("%d", &id[i]);
            for(int j = 0; j < m; ++j){
                dp[i][j] = max(dp[i][j], dp[i-1][j]*a[j][id[i]]);
                dp[i][id[i-1]] = max(dp[i][id[i-1]], dp[i-1][j]*a[id[i-1]][id[i]]);
            }
        }
        double ans = 0;
        for(int j = 0; j < m; ++j) ans = max(ans, dp[n-1][j]);
        printf("%.6f\n", ans);
    }
    return 0;
}



zoj-3736-Pocket Cube

problem

二阶魔方,给你初态,问n步内,最多可以让几个面颜色一样。

think

暴力。

code

const int K = 24;

struct point{
    int a[K];
};
int ans;

int num(point p){
    int res = 0;
    if(p.a[0] == p.a[1] && p.a[0] == p.a[2] && p.a[0] == p.a[3]) ++res;
    if(p.a[6] == p.a[7] && p.a[6] == p.a[12] && p.a[6] == p.a[13]) ++res;
    if(p.a[16] == p.a[17] && p.a[16] == p.a[18] && p.a[16] == p.a[19]) ++res;
    if(p.a[4] == p.a[5] && p.a[4] == p.a[10] && p.a[4] == p.a[11]) ++res;
    if(p.a[20] == p.a[21] && p.a[20] == p.a[22] && p.a[20] == p.a[23]) ++res;
    if(p.a[8] == p.a[9] && p.a[8] == p.a[14] && p.a[8] == p.a[15]) ++res;
    return res;
}

point t0(point p){
    point res = p;
    res.a[1] = p.a[7];
    res.a[3] = p.a[13];
    res.a[7] = p.a[17];
    res.a[13] = p.a[19];
    res.a[17] = p.a[21];
    res.a[19] = p.a[23];
    res.a[21] = p.a[1];
    res.a[23] = p.a[3];
    res.a[9] = p.a[8];
    res.a[8] = p.a[14];
    res.a[15] = p.a[9];
    res.a[14] = p.a[15];
    return res;
}
point t1(point p){
    point res = p;
    res.a[1] = p.a[21];
    res.a[3] = p.a[23];
    res.a[7] = p.a[1];
    res.a[13] = p.a[3];
    res.a[17] = p.a[7];
    res.a[19] = p.a[13];
    res.a[21] = p.a[17];
    res.a[23] = p.a[19];
    res.a[9] = p.a[15];
    res.a[8] = p.a[9];
    res.a[15] = p.a[14];
    res.a[14] = p.a[8];
    return res;
}

point t2(point p){
    point res = p;
    res.a[3] = p.a[5];
    res.a[2] = p.a[11];
    res.a[5] = p.a[16];
    res.a[11] = p.a[17];
    res.a[16] = p.a[14];
    res.a[17] = p.a[8];
    res.a[14] = p.a[3];
    res.a[8] = p.a[2];
    res.a[7] = p.a[6];
    res.a[6] = p.a[12];
    res.a[13] = p.a[7];
    res.a[12] = p.a[13];
    return res;
}

point t3(point p){
    point res = p;
    res.a[3] = p.a[14];
    res.a[2] = p.a[8];
    res.a[5] = p.a[3];
    res.a[11] = p.a[2];
    res.a[16] = p.a[5];
    res.a[17] = p.a[11];
    res.a[14] = p.a[16];
    res.a[8] = p.a[17];
    res.a[7] = p.a[13];
    res.a[6] = p.a[7];
    res.a[13] = p.a[12];
    res.a[12] = p.a[6];
    return res;
}

point t4(point p){
    point res = p;
    res.a[4] = p.a[6];
    res.a[5] = p.a[7];
    res.a[6] = p.a[8];
    res.a[7] = p.a[9];
    res.a[8] = p.a[23];
    res.a[9] = p.a[22];
    res.a[23] = p.a[4];
    res.a[22] = p.a[5];
    res.a[0] = p.a[2];
    res.a[2] = p.a[3];
    res.a[1] = p.a[0];
    res.a[3] = p.a[1];
    return res;
}

point t5(point p){
    point res = p;
    res.a[4] = p.a[23];
    res.a[5] = p.a[22];
    res.a[6] = p.a[4];
    res.a[7] = p.a[5];
    res.a[8] = p.a[6];
    res.a[9] = p.a[7];
    res.a[23] = p.a[8];
    res.a[22] = p.a[9];
    res.a[0] = p.a[1];
    res.a[2] = p.a[0];
    res.a[1] = p.a[3];
    res.a[3] = p.a[2];
    return res;
}

void solve(point p, int n){
    if(n < 0 || ans == 6) return;
    ans = max(ans, num(p));
    solve(t0(p), n-1);
    solve(t1(p), n-1);
    solve(t2(p), n-1);
    solve(t3(p), n-1);
    solve(t4(p), n-1);
    solve(t5(p), n-1);
}

int main () {
    int n;
    while(scanf("%d", &n) != EOF){
        point p;
        for(int i = 0; i < K; ++i){
            scanf("%d", &p.a[i]);
        }
        ans = 0;
        solve(p, n);
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值