Codeforces Round#393 div2

A. Petr and a calendar(模拟)
http://codeforces.com/problemset/problem/760/A

题意:已知2017年m月1日是星期d,求这个月日历有多少行。

算法:简单模拟或者直接用公式算这里写图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int main()
{
    int m, d;
    scanf("%d %d", &m, &d);
    int column = 1;
    for (int i = 1; i <= month[m-1]; i++)
        if ((d == 7) && (i < month[m-1]))
        {
            d = 1;
            column++;
        }
        else
            d++;
    printf("%d", column);
    return 0;
}

B. Frodo and pillows(二分答案+贪心)
http://codeforces.com/problemset/problem/760/B

题意:已知n个正整数的和为m,要求相邻两数差不超过1,求第k个数的最大值。

算法:我们在区间这里写图片描述上二分答案,相应的check(x)函数返回第k个数为x时的最小总数是否超过m。若第k个数为x,则第k±1个数为x-1,第k±2个数为x-2,以此类推,直到变为1或者达到首尾。根据等差数列求和公式,易知当第k个数的一边有y个数时,这y个数的和这里写图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, m, k;
LL sum(LL x, LL y)
{
    if (y > x-1)
        return (x-1)*x/2 + y-(x-1);
    else
        return (x-1+x-y)*y/2;
}
bool check(LL x)
{   
    if (sum(x, k-1)+x+sum(x, n-k) <= m) 
        return 1; 
    else 
        return 0;
}
int main()
{
    scanf("%d %d %d", &n, &m, &k);
    LL low = 1;
    LL hgh = m+1;
    while (low < hgh-1)
    {
        LL mid = (low+hgh)>>1;
        if (check(mid))
            low = mid;
        else
            hgh = mid;
    }
    printf("%d", low);
    return 0;
}

C. Pavel and barbecue(DFS)
http://codeforces.com/problemset/problem/760/C

题意:已知排列p和数列这里写图片描述,每个时刻将i位置烤串移动到位置这里写图片描述,并且若这里写图片描述则将烤串翻转一次。求对p和b最少一共修改多少次,可以使每个烤串在每个位置被烤两面后能回到原位置。

算法:
1.若每个烤串遍历每个位置后回到原位置,则整个遍历过程形成一个环。当遍历出若干个环时,我们只需要DFS统计环的个数即可(每个环修改一条边与相邻的环相连最后必能形成一个大环)。
2.每个烤串一共被翻转这里写图片描述次最后朝向是这里写图片描述。易知若这里写图片描述为奇数则不要修改b;若这里写图片描述为偶数则只需要再修改一次(将任意一个这里写图片描述改为1即可)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define MAXN 300000
#define FOR(i, N) for (int i=1; i<=N; i++)
int n;
int p[MAXN];
bool vis[MAXN];
void DFS(int x)
{
    if (!vis[p[x]])
    {
        vis[p[x]] = 1;
        DFS(p[x]);
    }
}
int main()
{
    int bi, res = 0, sum = 0;
    scanf("%d", &n);
    FOR(i, n) scanf("%d", &p[i]);
    FOR(i, n)
    {
        scanf("%d", &bi);
        sum += bi;
    }
    if (sum%2 == 0) res = 1;
    int cnt = 0;
    memset(vis, 0, sizeof(vis));
    FOR(i, n) 
        if (!vis[i])
        {
            vis[i] = 1;
            DFS(i);
            cnt++;
        }
    if (cnt == 1) 
        printf("%d", res);
    else
        printf("%d", res+cnt);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值