JZOJ 5207【GDOI2018模拟7.7】暴力大神hxx

题目描述:

这里写图片描述
有26重循环,1<=x,y<= 105

题解:

我们注意到x,y最多只有一个是变量,于是我们可以连出一个森林。
设f[i][j]为底i重循环选j,它和它的子树的方案数。
直接求和,乘起来即可。
最后求答案就是把各棵树根的方案数乘起来。

Code:

#include<cstdio>
#define ll long long
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
using namespace std;

const ll mo = 12015858;
ll n, b[27][27], f[27][100005], s[27][100005];
struct node {
    ll x, y;
}a[27][2];

void get(node &a) {
    char c = ' '; for(;!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')); c = getchar());
    if(c >= 'a' && c <= 'z') {
        a.x = 1; a.y = c - 'a' + 1;
    } else {
        a.x = 0;
        for(;c >= '0' && c <= '9'; c = getchar()) a.y = a.y * 10 + c - 48;
    }
}

void Init() {
    scanf("%lld", &n);
    fo(i, 1, n) get(a[i][0]), get(a[i][1]);
    fo(i, 1, n) {
        if(a[i][0].x) b[a[i][0].y][++ b[a[i][0].y][0]] = i;
        if(a[i][1].x) b[a[i][1].y][++ b[a[i][1].y][0]] = i;
    }
}

void dg(ll x) {
    fo(i, 1, 100000) f[x][i] = 1;
    fo(i, 1, b[x][0]) {
        ll y = b[x][i];
        dg(y);
        fo(j, 1, 100000) {
            if(a[y][0].x) {
                if(j <= a[y][1].y)
                    f[x][j] *= s[y][a[y][1].y] - s[y][j - 1]; else f[x][j] = 0;
            } else {
                if(a[y][0].y <= j)
                    f[x][j] *= s[y][j] - s[y][a[y][0].y - 1]; else f[x][j] = 0;
            }
            f[x][j] = (f[x][j] % mo + mo) % mo;
        }
    }
    fo(i, 1, 100000) s[x][i] = (s[x][i - 1] + f[x][i]) % mo;
}

void End() {
    ll ans = 1;
    fo(i, 1, n) if(!(a[i][0].x || a[i][1].x))
        dg(i), ans *= s[i][a[i][1].y] - s[i][a[i][0].y - 1], ans = (ans % mo + mo) % mo;
    printf("%lld", ans);
}

int main() {
    Init();
    End();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值