Codeforces Round 341 div2

Codeforces Round 341 div2
题目链接:
通过数:3(一题被叉一题未看懂)
Standing:310/5929
Rating change: 1862-1869
比赛总结:
题目都属于可以理解可以做的范围,原来以为要变色了……

A:
所有数任意选,求最大的和且和为偶数的值。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
#define LL long long
const int MAXN = 100000 + 5;
LL a[MAXN];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF){
        int cnt = 0;
        LL sum = 0;
        for(int i = 0 ; i < n ; i++){
            LL u;
            scanf("%I64d", &u);
            if(u % 2 == 1) a[cnt++] = u;
            sum += u;
        }
        if(sum % 2 == 0) printf("%I64d\n", sum);
        else{
            sort(a, a + cnt);
            printf("%I64d\n", sum - a[0]);
        }
    }
    return 0;
}

B:
坐标,发现就是y=x+b和y=-x+b上,所以直接换了个坐标系。
好像有更复杂的写法,然而不想补了

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
const int MAXN = 4000 + 100;
int c1[MAXN], c2[MAXN];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF){
        memset(c1, 0, sizeof(c1));
        memset(c2, 0, sizeof(c2));
        LL ans = 0;
        for(int i = 0 ; i < n ; i++){
            int x, y;
            scanf("%d%d", &x, &y);
            int u = x - y + 1000;
            int v = x + y + 1000;
            ans += c1[u]; c1[u]++;
            ans += c2[v]; c2[v]++;
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

C:
刚开始没看懂题,看懂后秒过了。求相邻一对取数能取到p的倍数的概率,这还用想吗

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 100000 + 5;
int l[MAXN], r[MAXN];
double lv[MAXN];
double dp[MAXN][3];
int n, p;
double cal(int i)
{
    return 1 - (1 - lv[i - 1]) * (1 - lv[i]) ;
}
int main()
{
    while(scanf("%d%d", &n, &p) != EOF){
        for(int i = 1 ; i <= n ; i++){
            scanf("%d%d", &l[i], &r[i]);
            int u1 = l[i] / p, v1 = l[i] % p;
            int u2 = r[i] / p, v2 = r[i] % p;
            int temp = u2 - u1;
            if(v1 == 0) temp++;
            lv[i] = 1.0 * temp / (r[i] - l[i] + 1);
        }
        l[0] = l[n], r[0] = r[n]; lv[0] = lv[n];
        l[n + 1] = l[1], r[n + 1] = r[1]; lv[n + 1] = lv[1];
//        for(int i = 0 ; i <= n + 1 ; i++) printf("lv[%d] = %f\n", i, lv[i]);
        double ans = 0;
        for(int i = 1 ; i <= n ; i++){
            ans += cal(i) * 2000;
//            printf("cal[%d] = %f\n", i, cal(i));
        }
//        memset(dp, 0, sizeof(dp));
//        for(int i = 1 ; i <= n + 1; i++){
//            if(i == 1){
//                dp[i][0] = (1 - lv[i]);
//                dp[i][1] = lv[i];
//            }
//            else{
//                dp[i][0] = (1 - lv[i]) * (dp[i - 1][1]);
//                dp[i][1] = lv[i] * (dp[i - 1][1] + dp[i - 1][0]);
//            }
//            printf("dp[%d][0] = %f, dp[%d][1] = %f\n", i, dp[i][0], i, dp[i][1]);
//        }
//        double ans = (dp[n + 1][0] + dp[n + 1][1]) * 1000 * n;
        printf("%.6f\n", ans);
    }
    return 0;
}

D:
因为之前写过一个处理这种大数的题,所以得意忘形的开loglog处理就没管了……然而忘记了对数的性质。
笨办法是分类讨论,水办法是long double。
看到一种神做法,把数看成实数,然后排序……贴一下
转侵删
If x > 1, then log(log(x)) is an increasing function, and if x < 1, thenreal(log(log(x))) is a decreasing function, because taking a logarithm of a negative number results in something like this:log( - x) = log( - 1 * x) = log( - 1) + logx = iπ + log(x). (Assuming log(x) is done in base e) Therefore, to compare two numbers by their loglog, you can do something like this:
bool compare (complex x, complex y) {
if (imag(x) == 0 and imag(y) == 0)
return real(x) > real(y);
else if (imag(x) != 0 and imag(y) == 0)
return false;
else if (imag(x) == 0 and imag(y) != 0)
return true;
else if (imag(x) != 0 and imag(y) != 0)
return real(x) < real(y);}

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define inf (1000000007)
double a[20];
double cal1(double x, double y, double z)
{
    double ans;
    ans = z * log(y) + log(log(x));
//    printf("x = %f, y = %f, z = %f\n");
//    printf("first part = %f\nsecond part = %f\n", z * log(y), log(log(x)));
//    system("pause");
//    printf("ans = %f\n", ans);
    return ans;
}
double cal2(double x, double y, double z)
{
    double ans;
    ans = log(y) + log(z) + log(log(x));
    return ans;
}
int solve(double x, double y, double z)
{
    for(int i = 1 ; i <= 12 ; i++) a[i] = -inf;
    if(x <= 1 && y <= 1 && z <= 1){
        double xx = 1.0 / x, yy = 1.0 / y, zz = 1.0 / z;
        if(xx != 1){
            a[1] = cal1(xx, y, z);
            a[2] = cal1(xx, z, y);
            a[3] = cal2(xx, y, z);
            a[4] = cal2(xx, z, y);
        }
        if(yy != 1){
            a[5] = cal1(yy, x, z);
            a[6] = cal1(yy, z, x);
            a[7] = cal2(yy, x, z);
            a[8] = cal2(yy, z, x);
        }
        if(zz != 1){
            a[9] = cal1(zz, x, y);
            a[10] = cal1(zz, y, x);
            a[11] = cal2(zz, x, y);
            a[12] = cal2(zz, y, x);
        }
        int re = 1;
        double mmax = a[1];
        for(int i = 1 ; i <= 12 ; i++){
            if(a[i] < mmax) mmax = a[i], re = i;
        }
        return re;
    }
    else{
        if(x > 1){
        a[1] = cal1(x, y, z);
        a[2] = cal1(x, z, y);
        a[3] = cal2(x, y, z);
        a[4] = cal2(x, z, y);
        }
        if(y > 1){
        a[5] = cal1(y, x, z);
        a[6] = cal1(y, z, x);
        a[7] = cal2(y, x, z);
        a[8] = cal2(y, z, x);
        }
        if(z > 1){
        a[9] = cal1(z, x, y);
        a[10] = cal1(z, y, x);
        a[11] = cal2(z, x, y);
        a[12] = cal2(z, y, x);
        }
    }
//    for(int i = 1 ; i <= 12 ; i++)
//        printf("%f\n", a[i]);
//    printf("\n");
    int re = 1;
    double mmax = a[1];
    for(int i = 1 ; i <= 12 ; i++){
        if(a[i] > mmax) mmax = a[i], re = i;
    }
    return re;
}
int out[5];
void print(int mark)
{
    if(mark == 1) printf("x^y^z\n");
    if(mark == 2) printf("x^z^y\n");
    if(mark == 3) printf("(x^y)^z\n");
    if(mark == 4) printf("(x^z)^y\n");

    if(mark == 5) printf("y^x^z\n");
    if(mark == 6) printf("y^z^x\n");
    if(mark == 7) printf("(y^x)^z\n");
    if(mark == 8) printf("(y^z)^x\n");

    if(mark == 9) printf("z^x^y\n");
    if(mark == 10) printf("z^y^x\n");
    if(mark == 11) printf("(z^x)^y\n");
    if(mark == 12) printf("(z^y)^x\n");
}
int main()
{
//    printf("log(3.4) = %f, loglog(1.1) = %f\n", log(3.4), log(log(1.1)));
    double x, y, z;
    while(cin >> x >> y >> z){
//    x *= 10, y *= 10, z *= 10;
//        x *= 1000, y *= 1000, z *= 1000;
        int mark = solve(x, y, z);
        print(mark);
    }
//    }
    return 0;
}

E:
这题改了一天……
题目意思说凑一个b位的数,要求它mod(x)==k。问有几种凑法。
首先按照数位dp思想。设dp[i][j]表示i位余数为j有多少种情况。然后发现这是一个矩阵快速幂,因为dp[i]可以由dp[i-1]得到。
然而那个矩阵怎么表示?因为乘式表示位dp[i-1]*T=dp[i],想到半夜得到的结果是T[i][j]表示当前余数为i、新添加j时得到余数为j的矩阵。T的初始化见代码,解释的意思是刚开始只有0位时,余数不定。然后由于dp[0] = {1,0,0,…0},故输出T[0][k]即可。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
#define mod (1000000007)
const int MAXN = 100 + 5;
struct Matrix
{
    LL a[MAXN][MAXN];
    int len;
    Matrix(){memset(a, 0, sizeof(a));}
    void init(int _len){
        len = _len;
        for(int i = 0 ; i < len ; i++){
            for(int j = 0 ; j < len ; j++){
                if(i == j) a[i][j] = 1;
                else a[i][j] = 0;
            }
        }
    }

    Matrix operator + (const Matrix &rbs)const{
        Matrix res;
        res.len = len;
        for(int i = 0 ; i < len ; i++)
            for(int j = 0 ; j < len ; j++) res.a[i][j] = (a[i][j] + rbs.a[i][j]) % mod;
        return res;
    }

    Matrix operator * (const Matrix &rbs)const{
        Matrix res;
        res.len = len;
        for(int i = 0 ; i < len ; i++){
            for(int k = 0 ; k < len ; k++){
                for(int j = 0 ; j < len ; j++)
                    res.a[i][j] = (res.a[i][j] + a[i][k] * rbs.a[k][j]) % mod;
            }
        }
        return res;
    }
    void print(){
        for(int i = 0 ; i < len ; i++){
            for(int j = 0 ; j < len ; j++) printf("%I64d ", a[i][j]);
            printf("\n");
        }
    }
};
Matrix ppow(Matrix u, int b)
{
    Matrix ans;
    ans.init(u.len);
    for(int i = b ; i ; i >>= 1){
        if(i & 1) ans = (ans * u);
        u = (u * u);
//        ans.print();
//        printf("\n");
//        u.print();
//        system("pause");
    }
    return ans;
}
int n, b, k, x;
LL g[MAXN];
LL out[MAXN];
int main()
{
    while(scanf("%d%d%d%d", &n, &b, &k, &x) != EOF){
        memset(g, 0, sizeof(g));
        int u;
        while(n--){
            scanf("%d", &u);
            g[u % x]++;
        }
        Matrix temp;
        temp.len = x;
        for(int i = 0 ; i < x ; i++){
            for(int j = 0 ; j < x ; j++){
                temp.a[i][(10 * i + j) % x] = g[j];
            }
        }
//        temp.print();
//        system("pause");
//        for(int i = 0 ; i < x ; i++){
//            for(int j = 0 ; j < x ; j++) printf("%I64d ", temp.a[i][j]);
//            printf("\n");
//        }
        temp = ppow(temp, b);
//        temp.print();
//        LL ans = 0;
//        for(int i = 0 ; i < x ; i++) ans = (ans + temp.a[k][i]) % mod;
//        printf("%I64d\n", ans);
//        for(int i = 0 ; i < x ; i++){
//            for(int j = 0 ; j < x ; j++) printf("%I64d ", temp.a[i][j]);
//            printf("\n");
//        }
//        memset(out, 0, sizeof(out));
//        for(int i = 0 ; i < x ; i++) for(int j = 0 ; j < x ; j++) out[i] = (out[i] + g[j] * temp.a[i][j]) % mod;
//        for(int i = 0 ; i < x ; i++) printf("%I64d ", out[i]);
//        printf("\n");
        printf("%I64d\n", temp.a[k][0]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值