CodeForces 305D Olya and Graph

来源:互联网 发布:淘宝基础店铺全屏店招 编辑:程序博客网 时间:2024/05/29 02:14

题目大意

给定一条单向链,上面有一些和链方向一致的边,每条边(包括加的)长度都是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