codeforces round #414 div1+div2

A:判断一下就可以了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a, b, c, n;
ll ans;
int main()
{
    scanf("%d%d%d%d", &a, &b, &c, &n);
    for(int i = 1; i <= n; ++i)
    {
        int x; scanf("%d", &x);
        if(x > b && x < c) ++ans;
    }
    printf("%lld\n", ans);
    return 0;
}
View Code

B:1:sqrt(2)-1....

#include<bits/stdc++.h>
using namespace std;
int n;
double f;
int main()
{
    scanf("%d%lf", &n, &f);
    double t = f / (double)sqrt(n);
    for(int i = 1; i < n; ++i)
    {
        printf("%.15f ", t * (double)sqrt(i));
    }
    return 0;
}
View Code

C:贪心,第一个字符串只用前n-[n/2]个,后一个字符串只用后[n/2]个,每个字符串用两个指针,如果第一个字符串最小的比第二个字符串最大的小,那么第一个人将最小的字符放在最靠前的位置,同理第二个人将最大的字符放在最前的位置,如果第一个人最小的字符比第二个人最大的字符大,那么就把他最大的字符放在末尾,第二个人则将最小的字符放在末尾。

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
int n;
int cnt1[N], cnt2[N], ans[N];
char s[N], t[N];
int main()
{
    scanf("%s%s", s + 1, t + 1); n = strlen(s + 1);
    for(int i = 1; i <= n; ++i) ++cnt1[s[i] - 'a'];
    for(int i = 1; i <= n; ++i) ++cnt2[t[i] - 'a'];
    int pos1 = 0, pos2 = 25, l = 0, r = n + 1; 
    for(int i = 1; i <= n; ++i)
    {
        while(cnt1[pos1] == 0) ++pos1;
        while(cnt2[pos2] == 0) --pos2;
        if(i % 2 == 1)
        {
            if(pos1 < pos2) ans[++l] = pos1;
            else ans[--r] = pos1;
            --cnt1[pos1];
        }
        else
        {
            if(pos1 < pos2) ans[++l] = pos2;
            else ans[--r] = pos2;
            --cnt2[pos2];
        }
    } 
    for(int i = 1; i <= n; ++i) printf("%c", (char)(ans[i] + 'a'));
    return 0;
}
View Code

D:重点在于会有相同的颜色,如果没有的话,那么直接染色就可以了,因为这样限制是唯一的,一个点颜色为i,相邻只能用两种颜色i-1和i+1,那么很好办。这里我们用一个巧妙的办法去除相同颜色,一个点将自己放入自己的邻接表中,然后排序邻接表,如果两个点的邻接表相同那么他们肯定相邻,那么这两个点的颜色相同。我们设一个点的颜色为i,另一个点的颜色为i+1,那么相邻的点的颜色只能等于i或i+1,如果等于i-1或i+2的话肯定和两个点中的一个矛盾,那么既然所有的邻居都等于i或i+1,那么我们不妨把那个颜色为i+1的点颜色换为i,很显然不矛盾。然后我们就把颜色能够相同的点分类,画成一个大点,重新编号,构图,两个新的点相邻当且仅当他们的点集中有相邻的点,也就是说这两个点集是相邻的。这里我们可以知道如果一个新的点的度数>=3或者有环就是无解,否则直接染色。

#include<bits/stdc++.h>
using namespace std;
const int N = 600010, MaxCH = 20000000;
int n, m, pos, len;
char CH[MaxCH];
vector<int> G[N];
int fa[N], color[N], Hash[N], h[N], u[N], v[N], used[N], vis[N];
inline int read()
{
    int x = 0;
    while(CH[pos] < '0' || CH[pos] > '9') ++pos;
    while(CH[pos] >= '0' && CH[pos] <= '9') x = x * 10 + CH[pos++] - '0';
    return x; 
}
namespace dsu 
{
    inline int find(int x) { return x == fa[x] ? x : find(fa[x]); }
    inline void connect(int x, int y)
    {
        int u = find(x), v = find(y);
        if(u == v) return;
        fa[u] = v;
    }
} using namespace dsu;
void build()
{
    for(int i = 1; i <= m; ++i) if(h[u[i]] == h[v[i]])
        connect(u[i], v[i]);        
    for(int i = 1; i <= m; ++i) 
    {
        int x = find(u[i]), y = find(v[i]);
        if(x == y) continue;
        G[x].push_back(y); G[y].push_back(x);
    }
    for(int i = 1; i <= n; ++i) 
    {
        sort(G[i].begin(), G[i].end());
        G[i].erase(unique(G[i].begin(), G[i].end()), G[i].end());
        if(G[i].size() > 2) { puts("NO"); exit(0); }
    }
}
void dfs(int u, int last)
{
    used[color[u]] = 1; vis[u] = 1;
    for(int i = 0; i < G[u].size(); ++i)
    {
        int v = G[u][i]; if(v == last) continue;
        if(vis[v]) { puts("NO"); exit(0); }
        if(!used[color[u] - 1]) color[v] = color[u] - 1;
        else color[v] = color[u] + 1; 
        used[color[v]] = 1;
        dfs(v, u);
    }
}
int main()
{
    len = fread(CH, 1, MaxCH, stdin);
    CH[len] = ' ';
    n = read(); m = read();
    Hash[0] = 1; for(int i = 1; i <= n; ++i) Hash[i] = Hash[i - 1] * 123333, fa[i] = i, h[i] = Hash[i];
    for(int i = 1; i <= m; ++i)
    {
        u[i] = read(); v[i] = read();
        h[u[i]] += Hash[v[i]]; h[v[i]] += Hash[u[i]];
    } 
    build();
    color[find(1)] = 300000;
    dfs(find(1), 0);
    puts("YES");
    for(int i = 1; i <= n; ++i) printf("%d ", color[find(i)]);
    return 0;
}
View Code

E:我们可以知道假设我们二分答案x,把>=x的数标为1,<x的数标为0,那么第一个人就是想要剩下的一个数为1,第二个人反之。那么我们可以知道两个性质:

1.如果n为奇数,那么当且仅当中间的数等于1和他任意相邻的两个数其中为1的情况下第一个人能赢,也就是说x能取到

2.如果n为偶数,那么当且仅当中间的两个数都为1第一个人才能赢,也就是说x能取到

然后我们发现,既然对于任意一个x根据n必须满足上面的条件才能赢,那么也就是说答案只跟中间的几个数有关,因为一个答案必须满足使中间的数满足条件才可以

所以我们就有答案

n为奇数ans=min(a[t],max(a[t-1],a[t+1]))t=(n+1)/2,因为我们可以保住中间的数和两边的数之一,我们不能自己选择保哪个,只可意会不可言传,自己手画画就可以了。

n为偶数ans=max(a[t],a[t+1])t=n/2,保哪个数可以自己选择,手画一下就可以了。

对于取了k个我们只需要看每段连续n-k个元素的最大值就好了

#include<bits/stdc++.h>
using namespace std;
const int N = 300010;
int n;
int a[N], b[N], c[N], ans[N];
struct seg {
    int tree[N << 2];
    void build(int l, int r, int x, int *a)
    {
        if(l == r) { tree[x] = a[l]; return; }
        int mid = (l + r) >> 1;
        build(l, mid, x << 1, a); build(mid + 1, r, x << 1 | 1, a);
        tree[x] = max(tree[x << 1], tree[x << 1 | 1]);
    }
    int query(int l, int r, int x, int a, int b)
    {
        if(l > b || r < a) return 0;
        if(l >= a && r <= b) return tree[x];
        int mid = (l + r) >> 1;
        return max(query(l, mid, x << 1, a, b), query(mid + 1, r, x << 1 | 1, a, b));
    }
} t1, t2;
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i)
    {
        ans[n - 1] = max(ans[n - 1], a[i]);
        b[i] = min(a[i], max(a[i - 1], a[i + 1]));
        c[i] = max(a[i], a[i + 1]);
    }
    t1.build(1, n, 1, b); t2.build(1, n, 1, c);
    int l1, r1, l2, r2;
    if(n % 2 == 0) 
    {  l1 = n / 2; r1 = l1 + 1; l2 = r2 = n / 2; }
    else { l1 = r1 = (n + 1) / 2; l2 = n / 2; r2 = l2 + 1; }    
    for(int k = 0; k < n - 1; ++k)
        if((n - k) % 2 == 1) ans[k] = t1.query(1, n, 1, l1--, r1++);
        else ans[k] = t2.query(1, n, 1, l2--, r2++);
    for(int i = 0; i < n; ++i) printf("%d ", ans[i]);
    return 0;
}
View Code

F:线段树维护每位,调了好长时间,原因是要在程序顶端先pushdown一下,我没有这个习惯

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200010;
struct data {
    ll cnt[20];
    int nxt[20];
} tree[N << 2];
int n, q;
int a[N];
ll bin[20];
void pushdown(int x)
{
    static ll cnt[10]; static int nxt1[10], nxt2[10];
    memset(cnt, 0, sizeof(cnt)); 
    memset(nxt1, 0, sizeof(nxt1));
    memset(nxt2, 0, sizeof(nxt2));
    for(int i = 0; i <= 9; ++i) 
    {
        nxt1[i] = tree[x].nxt[tree[x << 1].nxt[i]];
        nxt2[i] = tree[x].nxt[tree[x << 1 | 1].nxt[i]];        
    }
    for(int i = 0; i <= 9; ++i) 
    {
        tree[x << 1].nxt[i] = nxt1[i]; 
        tree[x << 1 | 1].nxt[i] = nxt2[i]; 
    }
    for(int i = 0; i <= 9; ++i) cnt[tree[x].nxt[i]] += tree[x].cnt[i];
    for(int i = 0; i <= 9; ++i) 
    {
        tree[x].cnt[i] = cnt[i];
        tree[x].nxt[i] = i;
    } 
}
void build(int l, int r, int x)
{
    if(l == r)
    {
        int t = a[l], pos = -1;
        while(t) 
        {
            tree[x].cnt[t % 10] += bin[++pos];
            t /= 10; 
        }
        for(int i = 0; i <= 9; ++i) tree[x].nxt[i] = i;
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1);    
    for(int i = 0; i <= 9; ++i) tree[x].cnt[i] = tree[x << 1].cnt[i] + tree[x << 1 | 1].cnt[i];
    for(int i = 0; i <= 9; ++i) tree[x].nxt[i] = i;
}
void update(int l, int r, int x, int a, int b, int x1, int y1)
{
    pushdown(x);
    if(l > b || r < a) return;
    if(l >= a && r <= b)
    {
        tree[x].nxt[x1] = y1;
        pushdown(x);
        return;
    }
    int mid = (l + r) >> 1;
    update(l, mid, x << 1, a, b, x1, y1); update(mid + 1, r, x << 1 | 1, a, b, x1, y1);
    for(int i = 0; i <= 9; ++i) tree[x].cnt[i] = tree[x << 1].cnt[i] + tree[x << 1 | 1].cnt[i]; 
}
ll query(int l, int r, int x, int a, int b)
{    
    pushdown(x);
    if(l > b || r < a) return 0;
    if(l >= a && r <= b) 
    {        
        ll ans = 0;
        for(int i = 0; i <= 9; ++i) ans += (ll)i * tree[x].cnt[i];
        return ans;
    }
    int mid = (l + r) >> 1; ll x1, x2;
    pushdown(x);
    x1 = query(l, mid, x << 1, a, b); x2 = query(mid + 1, r, x << 1 | 1, a, b);
    return x1 + x2;
}
int main()
{
    scanf("%d%d", &n, &q);
    bin[0] = 1; for(int i = 1; i <= 16; ++i) bin[i] = bin[i - 1] * 10;
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    build(1, n, 1);
    while(q--)
    {
        int opt, l, r, x, y;
        scanf("%d", &opt);
        if(opt == 1)
        {
            scanf("%d%d%d%d", &l, &r, &x, &y);
            update(1, n, 1, l, r, x, y);
        }
        if(opt == 2)
        {
            scanf("%d%d", &l, &r);
            ll ans = query(1, n, 1, l, r);
            printf("%lld\n", ans); 
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/19992147orz/p/6858200.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值