HNOI2012解题报告
来源:互联网 发布:诸暨行知小学怎么样 编辑:程序博客网 时间:2024/05/21 01:28
HNOI2012解题报告
Author: Pengyihao
Day1 T1 双十字
思路
因为矩阵总的大小不超过
然后我们考虑枚举双十字中间线所在的列。
枚举下面这根横线所在的行。
然后对于这根横线形成的双十字的数量有影响的行,一定在其之上并且长度短于它。
于是对于每段连续的
这个贡献可以求一下子树的和。
那么每次计算下面这根横线的贡献的时候,直接找到它在
注意必须在第
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (LL i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (LL i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}using std::vector;const LL MAXN = 10010, MOD = 1000000009;vector<LL>line[MAXN];vector<LL>lr[MAXN], tp[MAXN], co[MAXN];LL r, c, n;struct Node { Node *ch[2], *fa; LL data1, data2, sum1, sum2, sum3, sz; void clear(); void update(); void rotate(); void insert(LL, LL); LL get_rnk(LL); void splay(Node*); Node *find_key(LL);} *treap;void Node::rotate(){ Node *pa = fa; fa = pa -> fa; pa -> fa = this; if (fa != NULL) { bool t = (fa -> ch[0] == pa ? 0 : 1); fa -> ch[t] = this; } bool t = (pa -> ch[0] == this ? 0 : 1); Node *chd = ch[t ^ 1]; ch[t ^ 1] = pa; pa -> ch[t] = chd; if (chd != NULL) chd -> fa = pa; pa -> update(); update();}void Node::splay(Node *top){ while (fa != top) { if (fa -> fa != top) { bool t = (fa -> fa -> ch[0] == fa ? 0 : 1); if (fa -> ch[t] == this) fa -> rotate(), rotate(); else rotate(), rotate(); } else rotate(); } if (top == NULL) treap = this;}LL Node::get_rnk(LL now){ Node *x = this; LL ret = 0; while (true) { if (x -> data1 == now) { return (x -> ch[0] == NULL ? 1 : x -> ch[0] -> sz + 1) + ret; } if (x -> data1 > now) { if (x -> ch[0] == NULL) return ret; x = x -> ch[0]; } else { if (x -> ch[1] == NULL) return x -> sz + ret; ret += (x -> ch[0] == NULL ? 1 : x -> ch[0] -> sz + 1); x = x -> ch[1]; } }}Node* Node::find_key(LL rnk){ Node *x = this; while (true) { if ((x -> ch[0] == NULL ? 1 : x -> ch[0] -> sz + 1) == rnk) return x; else if ((x -> ch[0] == NULL ? 1 : x -> ch[0] -> sz + 1) < rnk) { rnk -= (x -> ch[0] == NULL ? 1 : x -> ch[0] -> sz + 1); x = x -> ch[1]; } else x = x -> ch[0]; }}void Node::insert(LL now, LL now2){ if (treap == NULL) { Node *hr = new Node; hr -> ch[0] = hr -> ch[1] = hr -> fa = NULL; hr -> data1 = now; hr -> data2 = now2; treap = hr; treap -> update(); return; } LL rnk = treap -> get_rnk(now); if (rnk == 0) { Node *hr = new Node; hr -> ch[0] = hr -> fa = NULL; hr -> ch[1] = treap; hr -> data1 = now; hr -> data2 = now2; treap -> fa = hr; hr -> update(); treap = hr; } else if (rnk == treap -> sz) { Node *hr = new Node; hr -> ch[1] = hr -> fa = NULL; hr -> ch[0] = treap; hr -> data1 = now; hr -> data2 = now2; treap -> fa = hr; hr -> update(); treap = hr; } else { Node *hr = new Node; treap -> find_key(rnk) -> splay(NULL); treap -> find_key(rnk + 1) -> splay(treap); hr -> data1 = now; hr -> data2 = now2; hr -> ch[0] = NULL; hr -> ch[1] = treap -> ch[1]; hr -> fa = treap; treap -> ch[1] = hr; hr -> ch[1] -> fa = hr; hr -> update(); treap -> update(); }}void Node::clear(){ if (ch[0] != NULL) ch[0] -> clear(); if (ch[1] != NULL) ch[1] -> clear(); delete this;}void Node::update(){ sz = 1; sum1 = data1 * data2 % MOD; sum2 = (data1 * (data1 + 1) / 2) * data2 % MOD; sum3 = data2; if (ch[0] != NULL) { sz += ch[0] -> sz; sum1 = (sum1 + ch[0] -> sum1) % MOD; sum2 = (sum2 + ch[0] -> sum2) % MOD; sum3 = (sum3 + ch[0] -> sum3) % MOD; } if (ch[1] != NULL) { sz += ch[1] -> sz; sum1 = (sum1 + ch[1] -> sum1) % MOD; sum2 = (sum2 + ch[1] -> sum2) % MOD; sum3 = (sum3 + ch[1] -> sum3) % MOD; }}int main(){ freopen("cross.in", "r", stdin); freopen("cross.out", "w", stdout); in(r); in(c); in(n); FOR(i, 0, r + 1) { lr[i].resize(c + 2); tp[i].resize(c + 2); co[i].resize(c + 2); line[i].resize(c + 2); } FOR(i, 1, r) FOR(j, 1, c) line[i][j] = 1; FOR(i, 1, n) { LL x, y; in(x); in(y); line[x][y] = 0; } FOR(i, 1, r) { FOR(j, 1, c) { if (line[i][j] == 0) continue; if (j == 1 || line[i][j - 1] == 0) lr[i][j] = 0; else lr[i][j] = lr[i][j - 1] + 1; } DNF(j, c, 1) { if (line[i][j] == 0) continue; if (j == c || line[i][j + 1] == 0) lr[i][j] = 0; else chkmin(lr[i][j], lr[i][j + 1] + 1); } FOR(j, 1, c) if (line[i][j]) { if (i == 1 || !line[i - 1][j]) tp[i][j] = 0; else tp[i][j] = tp[i - 1][j] + 1; } } DNF(i, r, 1) { FOR(j, 1, c) if (line[i][j]) { if (i == r || !line[i + 1][j]) co[i][j] = 0; else co[i][j] = co[i + 1][j] + 1; } } treap = NULL; bool is_cleared = true; LL ans = 0; FOR(j, 1, c) { if (!is_cleared) { treap -> clear(); treap = NULL; is_cleared = true; } FOR(i, 1, r) { if (i > 2) { if (lr[i - 2][j] != 0 && line[i - 1][j]) { treap -> insert(lr[i - 2][j], tp[i - 2][j]); is_cleared = false; } } if (!line[i][j]) { if (!is_cleared) { treap -> clear(); treap = NULL; is_cleared = true; } continue; } LL now = lr[i][j]; if (now && treap != NULL) { LL rnk = treap -> get_rnk(now); if (rnk != 0) { Node *hr; if (rnk != treap -> sz) { treap -> find_key(rnk + 1) -> splay(NULL); treap -> find_key(rnk) -> splay(treap); hr = treap -> ch[0]; } else { treap -> find_key(rnk) -> splay(NULL); hr = treap; } LL fst = hr -> sum1 * now % MOD * co[i][j] % MOD; LL sec = hr -> sum2 * co[i][j] % MOD; ans = (ans + fst - sec) % MOD; } if (rnk != treap -> sz) { Node *hr; if (rnk != 0) { treap -> find_key(rnk) -> splay(NULL); treap -> find_key(rnk + 1) -> splay(treap); hr = treap -> ch[1]; } else { treap -> find_key(rnk + 1) -> splay(NULL); hr = treap; } LL valu = (now * now - now * (now + 1) / 2) * co[i][j] % MOD; ans = (ans + hr -> sum3 * valu % MOD) % MOD; } } } } printf("%lld\n", ans); return 0;}
Day1 T2 与非
思路
首先可以发现一个性质——NAND操作可以构成所有的位运算,这个手玩一下就出来了。
然后对于二进制的某两位,我们发现如果对于每一个操作数,他们的这两位都相同,那么不论怎么运算最后肯定还是相同的。
除了这种限制之外,就没有其它限制了。
意思是说,如果在必定相同的两位之间连一条边,那么会形成一个个联通块。联通块与联通块之间两两对于答案的贡献是独立的。
联通块可以用并查集维护。
于是就可以答案进行数位DP辣!!
对于答案的第
我们从高到低地做,如果边界的该位上为
其余的类似。
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(), f = 1; x = 0; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= f;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}const LL MAXN = 1010;LL n, k, l, r, tot, A[MAXN], fa[MAXN];LL find(LL x){ LL tmp = x, pre; while (tmp != fa[tmp]) tmp = fa[tmp]; while (x != tmp) pre = fa[x], fa[x] = tmp, x = pre; return tmp;}void merge(LL x, LL y){ LL fx = find(x), fy = find(y); if (fx != fy) fa[fx] = fy;}LL query(LL x){ if (x < 0) return 0; LL ret = 0, tmp = tot; static bool chose[100]; static bool how_chose[100]; memset(chose, false, sizeof chose); if (x > (1ll << (k)) - 1) return (1ll << tmp); DNF(i, k, 1) { if (!(x & (1ll << (i - 1)))) { LL fx = find(i); if (chose[fx]) { if (how_chose[fx] == 1) return ret; } else { chose[fx] = true; how_chose[fx] = 0; tmp--; continue; } } else { LL fx = find(i); if (chose[fx]) { if (how_chose[fx] == 1) continue; else { ret += (1ll << tmp); return ret; } } else { chose[fx] = true; how_chose[fx] = 1; tmp--; ret += (1ll << tmp); continue; } } } return ret + 1;}int main(){ freopen("nand.in", "r", stdin); freopen("nand.out", "w", stdout); in(n); in(k); in(l); in(r); FOR(i, 1, n) in(A[i]); FOR(i, 1, k) fa[i] = i; FOR(i, 1, k) { LL tmp = (1ll << (k)) - 1; FOR(j, 1, n) { if (A[j] & (1ll << (i - 1))) { tmp &= A[j]; } else tmp &= (A[j] ^ ((1ll << k) - 1)); } if (!(tmp & (1ll << (i - 1)))) { puts("WA"); } FOR(j, 1, k) if (j != i) { if (bool(tmp & (1ll << (j - 1))) == bool(tmp & (1ll << (i - 1)))) merge(i, j); } } FOR(i, 1, k) if (fa[i] == i) tot++; printf("%lld\n", query(r) - query(l - 1)); return 0;}
Day1 T3 排队
思路
首先放男同学,有
然后放老师,可以放到一起或分开放,方案分别为
最后放女同学。如果老师放在一起了,那么就要放一个女同学在老师中间;否则把老师看作男同学。
总方案为
代码
#include <iostream>#include <cstdio>#include <cstring>#define Max(x,y) ((x)>(y)?(x):(y))#define LL long long#define MOD 100000000using namespace std;struct bign{ int len; LL s[10000]; bign(){ len=1; memset(s,0,sizeof s); s[1]=1; } bign operator = (const LL &num){ len=1; s[1]=num; return *this; } bign operator + (const bign&num){ bign c;c.s[1]=0;c.len=Max(num.len,len); for(int i=1;i<=c.len;i++){ c.s[i+1]=(c.s[i]+s[i]+num.s[i])/MOD; c.s[i]=(c.s[i]+s[i]+num.s[i])%MOD; } if(c.s[c.len+1])c.len++; return c; } bign operator - (const bign&num){ bign c;c.s[1]=0;c.len=len; int x=0; for(int i=1;i<=c.len;i++){ c.s[i]=s[i]-num.s[i]+x; x=0; if(c.s[i]<0){ c.s[i]+=MOD; x=-1; } } while(!c.s[c.len]&&c.len>1)c.len--; return c; } bign operator * (const LL&num){ bign c;c.s[1]=0;c.len=len; for(int i=1;i<=c.len;i++){ c.s[i+1]=(c.s[i]+s[i]*num)/MOD; c.s[i]=(c.s[i]+s[i]*num)%MOD; } if(c.s[c.len+1])c.len++; return c; } bign operator * (const bign&num){ bign c;c.s[1]=0;c.len=len+num.len+1; for(int i=1;i<=len;i++) for(int j=1;j<=num.len;j++){ c.s[i+j]+=(c.s[i+j-1]+s[i]*num.s[j])/MOD; c.s[i+j-1]=(c.s[i+j-1]+s[i]*num.s[j])%MOD; } while(!c.s[c.len]&&c.len>1)c.len--; return c; } void out(){ for(int i=len;i>=1;i--){ if(i==len)printf("%lld",s[i]); else printf("%08lld",s[i]); } }};LL n,m,tmp,tmp2;bign ans1,ans2;int main(){ freopen("queue.in", "r", stdin); freopen("queue.out", "w", stdout); scanf("%lld%lld",&n,&m);tmp=n+4;tmp2=n+3; for(LL i=1;i<=n;i++){ ans1=ans1*i; ans2=ans2*i; } ans1=ans1*(n+1)*n; for(LL i=1;i<=m&&tmp>=0;i++){ tmp--; ans1=ans1*tmp; } for(LL i=1;i<=m-1&&tmp2>=0;i++){ tmp2--; ans2=ans2*tmp2; } ans2=ans2*2*m*(n+1); (ans1+ans2).out(); return 0;}
Day1 T4 矿场搭建
思路
首先双联通缩点,然后对于每个联通块,只需要每个叶子节点放一个出口就行了(不能放割点)。
方案个数的话乘法原理就好了。
注意只有一个双联通分量的情况要特判!!
代码
#include <bits/stdc++.h>const int MAXN = 1010, MAXM = 510;bool is[MAXN];int belong[MAXN];int dfn[MAXN], low[MAXN], INDEX, dot[MAXN], all, sz[MAXN];int n, cnt, head[MAXN], nxt[MAXM << 1], data[MAXM << 1], du[MAXN];template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch != EOF && (ch < '0' || ch > '9')) ch = getchar(); if (ch == EOF) exit(0); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}void add(int x, int y) { nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++; nxt[cnt] = head[y]; data[cnt] = x; head[y] = cnt++;}void dfs(int now, int rot, int fa) { int size = 0; bool flag = false; dfn[now] = low[now] = ++INDEX; for (int i = head[now]; i != -1; i = nxt[i]) if (!dfn[data[i]]) { size++; dfs(data[i], rot, now); low[now] = Min(low[now], low[data[i]]); if (low[data[i]] >= dfn[now]) flag = true; } else if (data[i] != fa) { low[now] = Min(low[now], dfn[data[i]]); } if (flag && (now != rot || size >= 2)) { dot[++dot[0]] = now; is[now] = true; }}void dfs2(int now) { dfn[now] = 1; for (int i = head[now]; i != -1; i = nxt[i]) if (!is[data[i]] && !dfn[data[i]]) { dfs2(data[i]); sz[all]++; belong[data[i]] = all; }}int TTT;int main() { freopen("mining.in", "r", stdin); freopen("mining.out", "w", stdout); while (true) { in(n); int dian = -1; if (!n) return 0; cnt = 0; all = 0; memset(du, 0, sizeof du); memset(is, 0, sizeof is); memset(dot, 0, sizeof dot); memset(dfn, 0, sizeof dfn); memset(low, 0, sizeof low); memset(head, -1, sizeof head); memset(belong, 0, sizeof belong); for (int i = 1; i <= n; i++) { int s, t; in(s); in(t); add(s, t); dian = std::max(dian, std::max(s, t)); } for (int i = 1; i <= dian; i++) if (!dfn[i]) dfs(i, i, -1); memset(dfn, 0, sizeof dfn); for (int i = 1; i <= dian; i++) if (!dfn[i] && !is[i]) { belong[i] = ++all; sz[all] = 1; dfs2(i); } if (all == 1) { printf("Case %d: %d %d\n", ++TTT, 2, dian * (dian - 1) / 2); continue; } for (int i = 1; i <= dian; i++) if (is[i]) { for (int j = head[i]; j != -1; j = nxt[j]) dfn[belong[data[j]]] = 0; for (int j = head[i]; j != -1; j = nxt[j]) if (!dfn[belong[data[j]]]) { dfn[belong[data[j]]] = true; du[belong[data[j]]]++; } } int tot = 0; long long fang = 1; for (int i = 1; i <= all; i++) { if (du[i] == 1) { tot++; if (sz[i] > 1) fang = fang * (sz[i]); } } printf("Case %d: %d %lld\n", ++TTT, tot, fang); } return 0;}
Day2 T1
这是一道计算几何的题目。
因为我还没有进行这个专题,所以我跳过了这道题目。
Day2 T2
这是一道计算几何的题目。
因为我还没有进行这个专题,所以我跳过了这道题目。
Day2 T3
思路
这个题目是一道
只需要从小的合并到大的中间就可以了。
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}const int MAXN = 100010;char command[10];int n, m, rnk[MAXN], fa[MAXN];struct Node { int data, sz, id; Node *ch[2], *fa; void update(); void splay(Node*); void rotate(); Node *find_key(int); void insert(Node*);} *to[MAXN];void Node::rotate(){ Node *pa = fa; fa = pa -> fa; if (fa != NULL) { bool t = fa -> ch[0] == pa ? 0 : 1; fa -> ch[t] = this; } pa -> fa = this; bool t = pa -> ch[0] == this ? 0 : 1; Node *chd = ch[t ^ 1]; pa -> ch[t] = chd; if (chd != NULL) chd -> fa = pa; ch[t ^ 1] = pa; pa -> update(); update();}void Node::splay(Node *top){ while (fa != top) { if (fa -> fa != top) { bool t = (fa -> ch[0] == this ? 0 : 1); if (fa -> fa -> ch[t] == fa) { fa -> rotate(); rotate(); } else rotate(), rotate(); } else rotate(); }}Node* Node::find_key(int rnk){ Node *hr = this; while (true) { int nowrnk; nowrnk = (hr -> ch[0] == NULL ? 1 : hr -> ch[0] -> sz + 1); if (nowrnk == rnk) return hr; if (nowrnk < rnk) { rnk -= nowrnk; hr = hr -> ch[1]; } else hr = hr -> ch[0]; }}void Node::update(){ sz = 1; if (ch[0] != NULL) sz += ch[0] -> sz; if (ch[1] != NULL) sz += ch[1] -> sz;}void Node::insert(Node *x){ bool t; Node *pos = this, *pa = NULL; while (pos != NULL) { pa = pos; if (x -> data > pos -> data) pos = pos -> ch[1], t = 1; else pos = pos -> ch[0], t = 0; } x -> fa = pa; if (pa != NULL) pa -> ch[t] = x; x -> ch[0] = x -> ch[1] = NULL; while (x != NULL) { x -> update(); x = x -> fa; }}void Ins(Node* now, Node* to){ if (now == NULL) return; Ins(now -> ch[0], to); Ins(now -> ch[1], to); to -> splay(NULL); to -> insert(now); now -> splay(NULL);}int find(int x){ int tmp = x, pre; while (tmp != fa[tmp]) tmp = fa[tmp]; while (x != tmp) pre = fa[x], fa[x] = tmp, x = pre; return tmp;}bool merge(int x, int y){ int fx = find(x), fy = find(y); return fx == fy ? false : fa[fx] = fy, true;}int main(){ freopen("neverland.in", "r", stdin); freopen("neverland.out", "w", stdout); in(n); in(m); FOR(i, 1, n) fa[i] = i; FOR(i, 1, n) in(rnk[i]); FOR(i, 1, n) { to[i] = new Node; to[i] -> data = rnk[i]; to[i] -> sz = 1; to[i] -> id = i; to[i] -> fa = to[i] -> ch[0] = to[i] -> ch[1] = NULL; } FOR(i, 1, m) { int x, y; in(x); in(y); if (merge(x, y)) { if (to[x] == NULL) printf("%d\n", x); to[x] -> splay(NULL); to[y] -> splay(NULL); if (to[x] -> sz < to[y] -> sz) { Ins(to[x], to[y]); } else Ins(to[y], to[x]); } } int q; in(q); while (q--) { scanf("%s", command); if (command[0] == 'Q') { int x, k; in(x); in(k); to[x] -> splay(NULL); if (to[x] -> sz < k) printf("-1\n"); else { printf("%d\n", to[x] -> find_key(k) -> id); } } else { int x, y; in(x); in(y); if (merge(x, y)) { to[x] -> splay(NULL); to[y] -> splay(NULL); if (to[x] -> sz < to[y] -> sz) { Ins(to[x], to[y]); } else Ins(to[y], to[x]); } } } return 0;}
Day2 T4 集合选数
思路
考虑一张表,将
满足一个性质:对于一个格子,它的右边的格子里的数字是它的
于是问题转化为在格子中选不相邻的数的方案数。
表的长宽不会很大,是
可能有很多张不相交的表。
状压dp就好了。
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (register int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (register int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}const int MOD = 1000000001;const int MAXN = 100010;bool vis[MAXN];int n, ans = 1;int map[18][18], end[18], f[2][MAXN << 1];void solve(int now){ int ret = 0; FOR(i, 1, 100000) { if (i == 1) map[1][i] = now; else map[1][i] = map[1][i - 1] * 2; if (map[1][i] > n) { //map[1][i] = -1; break; } vis[map[1][i]] = true; FOR(j, 2, 100000) { map[j][i] = map[j - 1][i] * 3; if (map[j][i] > n) { //map[j][i] = -1; break; } vis[map[j][i]] = true; } } end[0] = 0; bool t = 0; int all = 1; f[t ^ 1][0] = 1; bool first = true; FOR(i, 1, 100000) { if (map[i][1] <= n) { FOR(j, 1, 100000) if (map[i][j] > n) {end[i] = j - 1; break;} int limits1 = (1 << end[i]) - 1, limits2 = (1 << end[i - 1]) - 1; FOR(j, 0, limits1) { f[t][j] = 0; bool flag = true; if (!first && !f[t ^ 1][j]) continue; FOR(l, 2, end[i]) if ((j & (1 << (l - 1))) && (((j) & (1 << (l - 2))))) { flag = false; break; } if (!flag) continue; FOR(k, 0, limits2) { bool flag = true; if (!f[t ^ 1][k]) continue; FOR(l, 1, end[i]) { if ((j & (1 << (l - 1))) && (k & (1 << (l - 1)))) { flag = false; break; } } if (flag) f[t][j] = (f[t][j] + f[t ^ 1][k]) % MOD; } } } else { all = i - 1; break; } first = false; t ^= 1; } FOR(i, 0, (1 << (end[all] - 1))) ret = (ret + f[t ^ 1][i]) % MOD; ans = 1ll * ans * ret % MOD;}int main(){ freopen("set.in", "r", stdin); freopen("set.out", "w", stdout); in(n); FOR(i, 1, n) { if (!vis[i]) solve(i); } printf("%d\n", ans); return 0;}
- HNOI2012解题报告
- [HNOI2012]与非 解题报告
- [HNOI2012]矿场搭建 解题报告
- luogu解题报告:HNOI2012永无乡
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- Antiprime解题报告
- expr解题报告
- 华容道解题报告
- tju解题报告
- zju1062/pku1095解题报告
- UsacoGate解题报告 --- 序曲
- ZJU 2060 解题报告
- HNOI2011解题报告
- 实习第五天 工作总结
- c++作业6
- 输入adb shell 时 提示error: more than one device and emulator
- Unity3d
- HNOI2012解题报告
- 大日志文件中如何统计单词个数?及map按value排序lambda表达式版
- HNOI2014解题报告
- PHP日期和时间设置时区
- HNOI2015解题报告
- 51Nod-1574-排列转换
- ubuntu+vim+opencv+cmake环境搭建
- MATLAB学习笔记
- HNOI2017总结