Codeforces Round #353 (Div. 2) 模拟+贪心+乱搞

都退役了为什么打比赛呢
为什么一个半小时A掉了四个题呢
为什么rating涨了180呢
天啊……


A

题意:问首项为a公差为c的等差数列中是否含有b

mdzz…

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int SZ = 1000010;

bool check(LL a,LL b,LL c)
{
    if(c == 0)
    {
        if(a == b) return true;
        else return false;
    }
    if((b - a) % c == 0 && (b - a) / c + 1 > 0) return true;
    return false;
}

int main()
{
    LL a,b,c;
    cin >> a >> b >> c;
    if(check(a,b,c))
        puts("YES");
    else
        puts("NO");
    return 0;
}

/*

an - a1 = (n - 1) * d

*/

B

题意:一个3*3的九宫格,每个格子可以任意填[1,n]中的一个数,指定上下左右四个格子的值,问有多少种填数方案满足这个九宫格上面四个2 * 2的区域的和相等。

可以发现中间的格子不影响结果……暴力枚举左上填什么,然后判断一下是否合法,左上若合法则对答案的贡献是n,累加一下就行了……

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int SZ = 1000010;

int n,a,b,c,d;

bool iscz(int x)
{
    return x >= 1 && x <= n;
}

bool check(int x)
{
    int sum = a + b + x;
    if(!iscz(sum - b - d) || !iscz(sum - c - d) || !iscz(sum - a - c)) 
        return false;
    return true;
}

int main()
{
    LL ans = 0;
    scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);
    for(int i = 1;i <= n;i ++)
        if(check(i)) ans += n;
    printf("%I64d\n",ans);
    return 0;
}

/*

an - a1 = (n - 1) * d

*/

C

题意:环形的均分纸牌。每次操作是把第i个的数累加到第i个相邻位置上(1和n相邻),问最小操作次数使得最终序列全0。保证可以做到全0。

序列上的问题?均分纸牌。

环形?

考虑性质:序列中至少一个人会不往外分发纸牌,也就是说分纸牌是以他为结束的。
考虑操作过程:每次对一个序列进行操作,其实是统计前缀和不等于0的位置的个数。

所以,首先破环成链,然后枚举结束点。若以第i个人为结束,那么你需要统计[i+1,i+n+1]的区间中前缀和为0的个数,这里可以预处理整个2 * n的序列的前缀和,然后就变成统计[i+1,i+n+1]区间中sum[i]出现的个数,这个偷懒的可以直接写map。

因为枚举结束点,所以询问区间每次的端点移动是O(1)的,很好维护。复杂度是 O(nlogn) ,那个log是map的log。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;

typedef long long LL;
const int SZ = 1000010;
const int INF = 1000000010;
LL num[SZ],sum[SZ];

map<LL,int> mp;

int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
        scanf("%I64d",&num[i]),num[i + n] = num[i];
    for(int i = 1;i <= 2 * n;i ++)
        sum[i] = sum[i - 1] + num[i]; 

    for(int i = 2;i <= n + 1;i ++)
        mp[sum[i]] ++;

    int ans = INF;
    for(int i = 1;i <= n;i ++)
    {
        ans = min(ans,n - mp[sum[i]]);
        mp[sum[i + 1]] --; mp[sum[i + 1 + n]] ++;
    }
    printf("%d\n",ans);
    return 0;
}

/*

an - a1 = (n - 1) * d

[L,R] d 

1 2 3 -6 1 2 3 -6
1 3 6  0 1 3 6  0

2 5 -1 0
3 -3 -2 0

8
-1 0 0 0 0 0 0 1

*/

D

题意:给n个互不相同的数构成的序列,要求从第一个数为根,后面的数字按顺序依次插入形成二叉搜索树,问最终每个节点的父亲的权值是多少。

观察性质:每插入一个点,它会落到它所在的区间内,而它的父亲则是所在区间的两端点中较晚出现的那个,这个用一个set就可以维护。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;

typedef long long LL;
const int SZ = 1000010;
const int INF = 1000000010;

struct haha{
    int v,id;
};

bool operator <(haha a,haha b) { return a.v < b.v; } 

set<haha> S;

int main()
{
    int n;
    scanf("%d",&n);
    S.insert((haha){-INF,0}); S.insert((haha){INF,0});
    for(int i = 1;i <= n;i ++)
    {
        int x;
        scanf("%d",&x);
        if(i == 1) { S.insert((haha){x,i});continue; }
        set<haha> :: iterator it = S.lower_bound((haha){x,i});
        set<haha> :: iterator it2 = it; it2 --;
        if(it -> id > it2 -> id)
            printf("%d ",it -> v);
        else
            printf("%d ",it2 -> v);
        S.insert((haha){x,i});
    }
    return 0;
}


E

题意:一个长度为n的序列,其中第i个点向第[i+1,ai]的所有点连一条权值为1的有向边,问最后所有点对的最短路之和是多少。

没写,不会。退役选手表示不想写了……

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值