CodeForces 305D Olya and Graph

题目大意

给定一条单向链,上面有一些和链方向一致的边,每条边(包括加的)长度都是1,求有多少种方式加边可以使每一对 (i,j) 满足 i<j 有: dis(i,j)=ji dis(i,j)=jik

解答

由题目易知,所有边的长度必须是 k+1 的并且所有边的起点必须在一个 k+1 的连续区间中,所以,所有不满足上述条件的直接输出0,当 k+1>=n 时,直接输出1(没有可以连的边)。
如果并没有在链上的边,我们就可以在每一个长度为 k+1 的区间中随意连线
如果有边,就相当于确定了区间的范围
我们只需要找到第一个可以连边的区间,这个区间的方案数应为 2k+1 个,然后我们向后移1个,我们发现,最后一个不连边的方案,显然是包含在上一个区间中的,所以最后一个必须是连边的,故这个区间新增的方案数为 2k 个,由此即可得到答案

参考代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

const int MOD = 1000000007;

int n, m, k;
vector<int> ser;
int tw[1000005];
int l, r;

int main()
{
    tw[0] = 1;
    for (int i = 1; i < 1000005; i++)
        tw[i] = (tw[i-1] + tw[i-1]) % MOD;
    ios::sync_with_stdio(false);
    cin >> n >> m >> k;
    while (m--) {
        cin >> l >> r;
        if (r-l != 1 && r-l != k+1) {
            cout << "0";
            return 0;
        }
        if (r-l == k+1) {
            ser.push_back(r);
        }
    }
    k++;
    if (ser.size() >= 2) {
        if (ser[ser.size()-1] - ser[0] >= k) {
            cout << "0";
            return 0;
        }
    }
    if (k >= n) {
        cout << "1";
        return 0;
    }
    int m = ser.size();
    if (m == 0) {
        int ans = tw[min(n-k, k)];
        for (int i = k+k+1; i <= n; i++) {
            ans += tw[k-1];
            ans %= MOD;
        }
        cout << ans;
        return 0;
    }
    int ans = tw[min(n-k, k) - m];
    for (int i = max(ser[m-1], 2*k) + 1; i <= n && i-ser[0] < k; i++) {
        ans += tw[k-1-m];
        ans %= MOD;
    }
    cout << ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值