Codeforces Round #364 (Div. 2)【贪心、数学、尺取】

Codeforces 701


A. Cards

  直接贪心即可,写法各异。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
int N, a[105];
bool used[105] = {false};
set<int> st[105];
set<int>::iterator it;
int main()
{
    scanf("%d", &N);
    int sum = 0, ave;
    for(int i=1; i<=N; i++)
    {
        scanf("%d", &a[i]);
        sum += a[i];
        st[a[i]].insert(i);
    }
    ave = sum * 2 / N;
    for(int i=(N>>1), j; i>0; i--)
    {
        for(j=1; j<=N; j++) if(!used[j]) break;
        used[j] = true;
        int res = ave - a[j];
        for(it = st[res].begin(); it != st[res].end(); it++)
        {
            if(!used[*it])
            {
                used[*it] = true;
                printf("%d %d\n", j, *it);
                st[res].erase(it);
                break;
            }
        }
    }
    return 0;
}

 


B. Cells Not Under Attack

  记录每一行每一列是否被使用过,然后看是减去(行数+列数-1)(都是剩下行和剩下列),还是减去(行数)或者(列数),或者就是这个十字交点被用过的,于是就不减了。

  WA了一次,行列写错了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
ll N, sum, hang, lie;
int M;
bool du[100005] = {false}, lr[100005] = {false};
int main()
{
    scanf("%lld%d", &N, &M);
    sum = N * N;
    hang = lie = N;
    int x, y;
    while(M--)
    {
        scanf("%d%d", &x, &y);
        if(!du[x] && !lr[y])
        {
            sum -= hang + lie - 1;
            du[x] = true;
            lr[y] = true;
            hang--; lie--;
        }
        else if(!du[x])
        {
            sum -= lie;
            hang--;
            du[x] = true;
        }
        else if(!lr[y])
        {
            sum -= hang;
            lie--;
            lr[y] = true;
        }
        printf("%lld ", sum);
    }
    puts("");
    return 0;
}
/*
4 3
3 2
2 2
3 3
*/

 


C. They Are Everywhere

  尺取法,复杂度O(N)。不断尺取,去寻找最小值即为答案。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
inline int _id(char x)
{
    if(x >= 'a' && x <= 'z') return x - 'a';
    else return x - 'A' + 26;
}
const int maxN = 1e5 + 7;
int N, ans, sum = 0, type = 0, pos[55] = {0}, pre[maxN] = {0};
char s[maxN];
bool vis[55] = {false};
set<int> st;
int main()
{
    scanf("%d", &N); ans = N;
    scanf("%s", s + 1);
    for(int i=1, id; i<=N; i++)
    {
        id = _id(s[i]);
        pre[i] = pos[id];
        pos[id] = i;
        if(!vis[id])
        {
            vis[id] = true;
            sum++;
        }
    }
    for(int i=1; i<=N; i++)
    {
        if(!pre[i])
        {
            type++;
            st.insert(i);
        }
        else
        {
            st.erase(pre[i]);
            st.insert(i);
        }
        if(type == sum)
        {
            int tmp = (*st.rbegin()) - (*st.begin()) + 1;
            ans = min(ans, tmp);
        }
    }
    printf("%d\n", ans);
    return 0;
}

 


D. As Fast As Possible

  比较困难的数学题了(我物理果然是雾里(大雾)。

画出对应的t-x图:

我们可以列出一个方程组:
L = T_{all} * v_{1} + x *(v_{2} - v_{1})

T_{all}指的是总花费时间。

tim * x + (tim - 1) * y = T_{all}

我们假设每个bus向前的花费时间是x,返回接学生花费时间是y,那么,最优解的情况是每一位学生都能上车一次,因为车的载客量是K,所以我们的tim是N除以K向上取整。

S = (v_{2} - v_{1}) * x = (v_{2} + v_{1}) * y

然后连立这两个方程就可以通过x、y之间的固定关系求解了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-9
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
double L, v1, v2;
int N, K, tim;
int main()
{
    scanf("%d%lf%lf%lf%d", &N, &L, &v1, &v2, &K);
    tim = N / K + (bool)(N % K);
    double ans;
    double A = 1. * tim + 1. * (tim - 1.) * (v2 - v1) / (v2 + v1);
    double B = (v2 - v1) / A;
    ans = L / (B + v1);
    printf("%lf\n", ans);
    return 0;
}

 


E. Connecting Universities

  一个树上的思维操作,跟结点的size有关哦(非一般size,是有效size)

就是给出2*K个点(一开始我竟然读成了两千个点),然后我们可以画图来看,能发现其中的某些规律。

假设如图,红色的点是题目中说到 的2*K个点。

  那么如果要去找最优解,也就是应该这样配对{5, 6}、{1, 4}也可以是{1, 6}、{5, 4}。那么,我们可以从每条边产生的贡献角度来考虑这个问题,1-2这条边要贡献一次,3-5、2-3的边也是会贡献一次,然后为了达成最优解,2-4这条边必须贡献两次,4-6也是必须贡献一次才可以。所以我们不如去看如何处理每条边的贡献。

  那么问题似乎被简化了,我们把每个结点的入度的边等效给结点上面去,(代表了3这号点的代表边是2-3),3的子树当中有一个标记点;2的子树中有3个,但是呢一共就只有4个点,所以其实1-2的边只用了4-3=1次。我们要考虑目前点的size和2*K-size的关系。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-9
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7;
int N, K, head[maxN], cnt, siz[maxN] = {0};
bool op[maxN] = {false};
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN<<1];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
ll ans = 0;
void dfs(int u, int fa)
{
    siz[u] += op[u];
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        dfs(v, u);
        siz[u] += siz[v];
    }
    ans += min(siz[u], 2 * K - siz[u]);
}
inline void init()
{
    cnt = 0;
    for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
    scanf("%d%d", &N, &K);
    init();
    for(int i=(K<<1), x; i>=1; i--)
    {
        scanf("%d", &x); op[x] = true;
    }
    for(int i=1, u, v; i<N; i++)
    {
        scanf("%d%d", &u, &v);
        _add(u, v);
    }
    dfs(1, 0);
    printf("%lld\n", ans);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值