湖南2020多校对抗赛round1 NWERC2014

湖南2020多校对抗赛round1 NWERC2014

题目来源:http://codeforces.com/gym/101482

题号 赛中 赛后
A Around the Track ×
B Biking Duck ×
C Cent Savings
D Digi Comp II
E Euclidean TSP
F Finding Lines
G Gathering ×
H Hyacinth
I Indoorienteering ×
J Judging Troubles
K Knapsack Collection ×

C(动态规划):

题意:

给了你n个物品,每个物品的价值为pi,你最多可以将这n个物品分成d+1堆来购买这些物品,购买物品的规则是这样的,如果一堆物品的总价值为sum,那么购买这一堆物品的费用为sum的四舍五入的值,假设这一堆物品价值为126,那么购买他就需要130,假设这一堆物品价值为124,那么购买他就需要120元

求,购买这n个物品最少花费多少钱

题解:

\(dp[i][j]表示前i堆分成j堆最少需要花费多少钱\)

\(边界:dp[i][1]=getval(sum[i])\)

\(转移:dp[k][j] = min(dp[k][j], dp[i][j - 1] + getval(sum[k] - sum[i]));\)

\(时间复杂度:O(d*n^2)\)

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
#define debug4(x,y,z,m) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]"<<" ["<<#m<<" "<<m<<"]\n"

const int maxn = 2e3 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
    return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
    return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
    double ans = 1.0;
    while(b) {
        if(b % 2)ans = ans * a;
        a = a * a;
        b /= 2;
    } return ans;
}
LL quick_pow(LL x, LL y) {
    LL ans = 1;
    while(y) {
        if(y & 1) {
            ans = ans * x % mod;
        } x = x * x % mod;
        y >>= 1;
    } return ans;
}
int dp[maxn][30];
int a[maxn];
int sum[maxn];
int getval(int val) {
    if(val % 10 >= 5) {
        return val - val % 10 + 10;
    } else {
        return val - val % 10;
    }
}
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    int n, d;
    scanf("%d%d", &n, &d);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    memset(dp, INF, sizeof(dp));
    for(int i = 1; i <= n; i++) {
        dp[i][1] = getval(sum[i]);
        // debug1(dp[i][1]);
    }

    for(int i = 1; i <= n; i++) {
        for(int j = 2; j <= d + 1; j++) {
            for(int k = i + 1; k <= n; k++) {
                dp[k][j] = min(dp[k][j], dp[i][j - 1] + getval(sum[k] - sum[i]));
                // debug3(i, j, k);
                // debug3(dp[k][i], dp[i][j - 1], getval(sum[k] - sum[i - 1]));
            }
        }
    }
    int ans = INF;
    for(int i = 1; i <= d + 1; i++) {
        // debug1  (dp[n][i]);
        ans = min(dp[n][i], ans);
    }
    printf("%d\n", ans);
    return 0;
}

cwolf9定义状态是

前i堆最多可以节省多少钱

int n, m, k;
int dp[MXN][21], ar[MXN], pre[MXN];
int check(int a, int b) {
    int x = (pre[b]-pre[a]) % 10;
    int y = pre[b]-pre[a] - x;
    return (x>=5?x-10:x);
}
int main() {
#ifndef ONLINE_JUDGE
    // freopen("D:\\in.in", "r", stdin);
    // freopen("D:\\out.out", "w", stdout);
#endif
    n = read();
    m = read() + 1;
    for(int i = 1; i <= n; ++i) ar[i] = read(), pre[i] = pre[i-1] + ar[i];
    for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) dp[i][j] = - INF;
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= min(m, i); ++j) {
            for(int k = 0; k < i; ++k) {
                if(j == 1 && k > 0) continue;
                if(k >= j - 1) {
                    dp[i][j] = max(dp[i][j], dp[k][j-1] + check(k, i));
                }
            }
        }
    }
    int ans = INF;
    // printf("%d\n", pre[n]);
    for(int i = 1; i <= m; ++i) {
        ans = min(ans, pre[n] - dp[n][i]);
        // printf("%d\n", dp[n][i]);
    }
    printf("%d\n", ans);
#ifndef ONLINE_JUDGE
    cout << "time cost:" << 1.0 * clock() / CLOCKS_PER_SEC << "ms" << endl;
    system("pause");
#endif
    return 0;
}

D(拓扑排序):

题意:

有m个传送门,传送门分左右两边,每个传送门初始时都有一个状态“L”或者"R",现在有n个小球从1号节点出发,每到一个传送门就会被传送到传送门当前状态指向的节点,每次传送门传送完一个小球后就会将当前状态反转,保证可以到达终点0,问m个传送门最后的状态是怎么样的

题解:

可以解得,如果传送门被经过了奇数次,那么传送门的状态就会反转,否则传送门就不会改变状态,所以拓扑排序一遍后记录每个传送门被经过的次数就行了

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 5e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
    return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
    return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
    double ans = 1.0;
    while(b) {
        if(b % 2)ans = ans * a;
        a = a * a;
        b /= 2;
    } return ans;
}
LL quick_pow(LL x, LL y) {
    LL ans = 1;
    while(y) {
        if(y & 1) {
            ans = ans * x % mod;
        } x = x * x % mod;
        y >>= 1;
    } return ans;
}
struct node {
    int l, r;
    char sta[3];
} a[maxn];
int vis[maxn];
int in[maxn];
LL num[maxn];
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    LL n;
    int m;
    scanf("%lld%d", &n, &m);
    for(int i = 1; i <= m; i++) {
        scanf("%s %d %d", a[i].sta, &a[i].l, &a[i].r);
        in[a[i].l]++;
        in[a[i].r]++;
    }
    queue<int> q;

    num[1] = n;
    for(int i = 1; i <= m; i++) {
        if(in[i] == 0) {
            q.push(i);
        }
    }
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        if(num[u] % 2 == 1) vis[u] = 1;
        if(a[u].sta[0] == 'L') {
            num[a[u].l] += (num[u] - num[u] / 2);
            num[a[u].r] += num[u] / 2;
        } else {
            num[a[u].r] += (num[u] - num[u] / 2);
            num[a[u].l] += num[u] / 2;
        }
        in[a[u].l]--;
        if(in[a[u].l] == 0) {
            q.push(a[u].l);
        }
        in[a[u].r]--;
        if(in[a[u].r] == 0) {
            q.push(a[u].r);
        }
    }
    for(int i = 1; i <= m; i++) {
        if(vis[i] == 1) {
            if(a[i].sta[0] == 'L') {
                a[i].sta[0] = 'R';
            } else {
                a[i].sta[0] = 'L';
            }
        }
    }
    for(int i = 1; i <= m; i++) {
        printf("%c", a[i].sta[0]);
    }
    printf("\n");
    return 0;
}

E(三分):

题意:

根据题目给的公式和例可以猜出来time t=第二个公式的值和第三个公式的值

然后再反过去读题就知道

\((n * pow(log2(n), c * sqrt(2))) / (p * 1e9);\)

\(s * (1 + 1.0 / c) / v;\)

分别是题目给你的两个公式,第一个公式是一个关于c递增的公式,第二个公式是一个关于c递减的公式

那么时间的最小值是根据c来的,我们需要找到波谷

所以这里就可以想到是三分求波谷了

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
    return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
    return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
    double ans = 1.0;
    while(b) {
        if(b % 2)ans = ans * a;
        a = a * a;
        b /= 2;
    } return ans;
}
LL quick_pow(LL x, LL y) {
    LL ans = 1;
    while(y) {
        if(y & 1) {
            ans = ans * x % mod;
        } x = x * x % mod;
        y >>= 1;
    } return ans;
}
int n, m, k;
double p, s, v, c, t;
double first(double c) {
    return n * pow(log(n), c * sqrt(2));
}
double second(double c) {
    return (n * pow(log2(n), c * sqrt(2))) / (p * 1e9);
}
double third(double c) {
    return s * (1 + 1.0 / c) / v;
}
double get(double c) {
    return second(c) + third(c);
}
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    cin >> n >> p >> s >> v;
    double l = 0, r = 100, ans = 1e18, c;
    int T = 100;
    while(T--) {
        double lmid = l + (r - l) / 3.0;
        double rmid = r - (r - l) / 3.0;
        double Lans = get(lmid), Rans = get(rmid);
        if(Rans > Lans) {
            r = rmid;
            if(ans > Lans) ans = Lans, c = lmid;
        } else {
            l = lmid;
            if(ans > Rans) ans = Rans, c = rmid;
        }
    }
    printf("%.9f %.9f\n", ans, c);
    return 0;
}

F(随机):

题意:

平面上有n个点,问是否存在[n · p/100]向上取整个点在同一条直线上面

随机大法

证明如下:

\[假设这条直线存在 \\ 那么平面上就有n*p\%个以上的点就在直线上\\ 1.我们可以知道随便取出一个点,那么这个点在直线上的概率是p/100;\\ 2.随机选出两个点,那么这两个点都在直线上的概率就是p*p/10000;\\ 3.随机出来的两个点不在直线上的概率是(1-p*p/10000);\\ 4.随机k次出来两个点不在这条直线上的概率是(1-p*p/10000)^k\\ 5.所以随机的正确率是1-(1-p*p/10000)^k=(0.99999999999999999813261855332981‬)\\ \]

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define eps 1e-8
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef pair<int, int> PII;
const int MX = 1e6;
const int MM = 1e4;

namespace random {
    typedef unsigned ui;
    typedef long long ll;
    typedef unsigned long long ull;
    ui X, Y, Z, W; string str;
    char in[15], ou[15];
    void start() {
        srand ( (ui) time (NULL) );
        X = rand(), Y = X ^ rand(), Z = Y ^ rand();
    }
    ui RNG61() {
        X = X ^ (X << 11);
        X = X ^ (X >> 4);
        X = X ^ (X << 5);
        X = X ^ (X >> 14);
        W = X ^ Y ^ Z;
        X = Y;
        Y = Z;
        Z = W;
        return Z;
    }
    int Randint (int mod) {
        return RNG61() % mod + 1;
    }
    ll Randll(ll mod) {
        return ((ull)RNG61() << 32 | RNG61()) % mod + 1;
    }
    double Randdouble(int l, int r) {
        if(l == r) return l;
        if(l > r) swap(l, r);
        double ret = RNG61() % (r - l) + l;
        double tmp = RNG61();
        while(tmp > 1) tmp /= 10;
        ret += tmp;
        return ret;
    }
}
const int maxn = 1e5 + 5;
struct Point {
    int x, y;
} a[maxn];
bool check(Point t1, Point t2, Point t3) {
    int x1 = t1.x;
    int x2 = t2.x;
    int x3 = t3.x;
    int y1 = t1.y;
    int y2 = t2.y;
    int y3 = t3.y;
    if((y2 - y1) * (x3 - x2) == (y3 - y2) * (x2 - x1)) {
        return true;
    }
    return false;
}
using namespace random;
int main() {
    int n, p;
    scanf("%d%d", &n, &p);
    for(int i = 1; i <= n; i++) {
        scanf("%d%d", &a[i].x, &a[i].y);
    }
    int num = (n * p + 99) / 100;
    start();
    int T = 1000;
    int flag = 0;
    while(T--) {
        int x = Randint(n);
        int y = Randint(n);
        if(x == y) {
            y = x + 1;
        }
        Point t1 = a[x];
        Point t2 = a[y];
        int cnt = 0;
        for(int i = 1; i <= n; i++) {
            if(check(t1, t2, a[i])) {
                cnt++;
            }
        }
        if(cnt >= num) {
            flag = 1;
        }
    }
    if(flag) {
        printf("possible\n");
    } else {
        printf("impossible\n");
    }
}

H(贪心+dfs):

题意:

每个节点可以有一段波分的频率

如果两个相邻的节点有相同的频率,那么就可以使用其中的一个频率通信

现在给你一颗n个节点形成的树,现在让你给每个节点构造一段他自己的频率,使得,总的在使用中的频率个数最多,并且每个相邻的节点都要可以通信

题解:

要想在使用中的节点最多,那么每个频率至少用一次,假设a节点用了这个频率,那么他的所有儿子节点都要用上这个频率,可以先构造根节点的频率为【1 ,2】,然后从根节点往下走给每个子节点赋值和新建频率即可,这样可以保证在使用中的频率个数一定是最高的

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
    return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
    return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
    double ans = 1.0;
    while(b) {
        if(b % 2)ans = ans * a;
        a = a * a;
        b /= 2;
    } return ans;
}
LL quick_pow(LL x, LL y) {
    LL ans = 1;
    while(y) {
        if(y & 1) {
            ans = ans * x % mod;
        } x = x * x % mod;
        y >>= 1;
    } return ans;
}
struct EDGE {
    int v, nxt;
} edge[maxn << 1];
int head[maxn], tot;
void init() {
    memset(head, -1, sizeof(head));
    tot = 0;
}
void add_edge(int u, int v) {
    edge[tot].v = v;
    edge[tot].nxt = head[u];
    head[u] = tot++;
}
struct node {
    int x, y;
} a[maxn];
int in[maxn];
int vis[maxn];
int cnt = 2;
void dfs(int u, int fa) {
    if(u == 1) {
        for(int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].v;
            if(v == fa) continue;
            dfs(v, u);
        }
    } else {
        if(in[u] == 1 && u != 1) {
            a[u].x = a[fa].x;
            a[u].y = a[fa].y;
            vis[a[u].x]++;
            vis[a[u].y]++;
            return;
        }
        if(vis[a[fa].x] >= 2) {
            a[u].x = a[fa].y;
        } else {
            a[u].x = a[fa].x;
        }
        a[u].y = ++cnt;
        vis[a[u].x]++;
        vis[a[u].y]++;
        for(int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].v;
            if(v == fa) continue;
            dfs(v, u);
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    int n;
    scanf("%d", &n);
    init();
    for(int i = 1, u, v; i < n; i++) {
        scanf("%d%d", &u, &v);
        add_edge(u, v);
        add_edge(v, u);
        in[u]++;
        in[v]++;
    }

    a[1].x = 1;
    a[1].y = 2;
    vis[a[1].x]++;
    vis[a[1].y]++;
    cnt = 2;
    dfs(1, 0);
    for(int i = 1; i <= n; i++) {
        printf("%d %d\n", a[i].x, a[i].y);
    }
    return 0;
}

J(签到)

题意:

你有n份代码提交到两个评测鸡上面,顺序并不确定,问两个评测鸡最多有多少份代码的评测结果是一样的

题解:

存一下评测结果然后加一下就行

#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
    return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
    return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
    double ans = 1.0;
    while(b) {
        if(b % 2)ans = ans * a;
        a = a * a;
        b /= 2;
    } return ans;
}
LL quick_pow(LL x, LL y) {
    LL ans = 1;
    while(y) {
        if(y & 1) {
            ans = ans * x % mod;
        } x = x * x % mod;
        y >>= 1;
    } return ans;
}
map<string, int>mp1, mp2;

int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        string str;
        cin >> str;
        mp1[str]++;
    }
    for(int i = 1; i <= n; i++) {
        string str;
        cin >> str;
        mp2[str]++;
    }
    map<string, int>::iterator it;
    int ans = 0;
    for(it = mp1.begin(); it != mp1.end(); it++) {
        ans += min(mp1[it->first], mp2[it->first]);
    }
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/buerdepepeqi/p/12733707.html