Codeforces D TediousLee (规律 / 树上递推计数)

传送门

题意: 给你一个建树规则:
级别1的有根死灌木是单个顶点。为了构造级别i的RDB,首先,我们构造级别i-1的RDB,然后对于每个顶点u:

  • 如果您没有孩子,那么我们将添加一个孩子;
  • 如果你有一个孩子,那么我们将增加两个孩子;
  • 如果您有一个以上的孩子,那么我们将跳过它。

若出现含四个节点的根树(claw,如下图),且该四节点的爪子上的点都是绿色,则可将其都标记为黄色。Codeforces D TediousLee (规律 / 树上递推计数)_第1张图片

先给出n级别的树,试问最多能标记多少个黄色节点?答案对1e9+7取模。
Codeforces D TediousLee (规律 / 树上递推计数)_第2张图片
思路:

  • 其实推到5级树便会发现一定规律,每个节点都可作为根节点,于是每个节点都可以开始新的树。
  • 对于 i 级树就由两个 i-1级树,一个 i-2 级树和一个根节点组成。因此可以推出 i 级树的claw数cnt[i] = cnt[i-1]*2 + cnt[i-2]。
  • 但还需要考虑那个根节点可能的贡献,若两个 i-1级树和 i-2 级树的根节点都未做出贡献(任然是绿色),那么又可和根节点组成一个新的claw。
  • 这里用一个add[i]来标记 i 级树的根节点是否有贡献,故当add[i-1]和add[i-2]都为0时,cnt[i] ++,add[i] = 1;否则add[i] = 0。
  • 感谢大佬博客的启发,详细思路与图解可参见大佬博客。

代码实现:

#include
#define endl '\n'
#define null NULL
#define ll long long
#define int long long
#define pii pair
#define lowbit(x) (x &(-x))
#define ls(x) x<<1
#define rs(x) (x<<1+1)
#define me(ar) memset(ar, 0, sizeof ar)
#define mem(ar,num) memset(ar, num, sizeof ar)
#define rp(i, n) for(int i = 0, i < n; i ++)
#define rep(i, a, n) for(int i = a; i <= n; i ++)
#define pre(i, n, a) for(int i = n; i >= a; i --)
#define IOS ios::sync_with_stdio(0); cin.tie(0);cout.tie(0);
const int way[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
using namespace std;
const int  inf = 0x7fffffff;
const double PI = acos(-1.0);
const double eps = 1e-6;
const ll   mod = 1e9 + 7;
const int  N = 2e6 + 5;

int t, n, add[N], cnt[N];

void Inint(){
    for(int i = 3; i < N; i ++){
        cnt[i] = (cnt[i-2]*2 + cnt[i-1])%mod;
        if(!add[i-2] && !add[i-1]) cnt[i] += 1, add[i] = 1;
    }
}

signed main()
{
    IOS;

    Inint();
    cin >> t;
    while(t --){
        cin >> n;
        cout << cnt[n]*4%mod << endl;
    }

    return 0;
}

你可能感兴趣的:(图论,妙啊)