关闭

CodeForces 305D Olya and Graph

标签: codeforces模拟
204人阅读 评论(0) 收藏 举报
分类:

题目大意

给定一条单向链,上面有一些和链方向一致的边,每条边(包括加的)长度都是1,求有多少种方式加边可以使每一对(i,j)满足i<j有:dis(i,j)=jidis(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;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:6221次
    • 积分:418
    • 等级:
    • 排名:千里之外
    • 原创:30篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    我的同学