题目描述:
有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();
}