A : 构造
B : 状压DP
C : 构造
D : 线段树或平衡树
E : 树链剖分+线段树
F : Unfinished
强行猜了一个结论,试了一下小数据发现没问题,那就假装没问题吧……就是外面一圈1~n-1,里面把1插在n-2和n-1之间,其他的顺次递推。
本题考察输出优化的使用。
#include
using namespace std;
namespace runzhe2000
{
int n, last = 1, sum, tot; char buff[20000000];
void print_char(char c){buff[++tot] = c;}
void print_int(int x)
{
if(x>9)print_int(x/10);
buff[++tot] = (x%10+'0');
}
void print_close(){puts(buff+1);}
void main()
{
scanf("%d",&n); n--; if(~n&1){puts("0");return;} sum = 3*(n+1)>>1;
for(int i = 1; i <= n; i++) print_int(i),print_char(' '); print_char('\n');
for(int i = 1; i <= n; i++) print_int(last = sum - ((i-1+n)%n?(i-1+n)%n:n) - last),print_char(' ');
print_close();
}
}
int main()
{
runzhe2000::main();
}
按数字从小到大做,记 f[i][s] 表示做到第i小的数字,此时已经填完的状态为s,枚举这个i填不填即可。
这样是 O(2n∗m) 的,理论上应该是可以过的,然而本机测了两种大同小异的大数据,一种全是1~20的正序循环的数据1s-跑出,另一种全是20~1的逆序循环7s+跑出。看了一下操作次数发现并没有什么问题,就很纳闷了。后来研究了一下,发现把可用状态丢进队列的话,内存访问很不连续,还不如直接顺序枚举所有状态……论不懂常数的危害QAQ
#include
#include
#include
#define N 22
#define M 105
#define cmax(u,v) ((u)<(v)?(u)=(v):0)
using namespace std;
namespace runzhe2000
{
const int INF = 1<<29;
int n, m, f[2][1<1<void main()
{
happy = scanf("%d%d",&n,&m);
for(int i = 0; i < (1<memset(f, -63, sizeof(f)); f[cur][0] = 0;
for(int i = 1, pos; i <= m; i++, cur ^= 1)
{
happy = scanf("%d",&pos);
int *fc = f[cur], *fcc = f[cur^1], p = 1<<(pos-1);
for(int s = (1<1; ~s; s--)
{
int v = fc[s];
cmax(fcc[s], v);
if(~s&p)
{
int ss = s | p, tmp = v + popcount[s>>pos];
cmax(fcc[ss], tmp);
}
fc[s] = -INF;
}
}
printf("%d\n",f[cur][(1<1]);
}
}
int main()
{
runzhe2000::main();
}
看上去好像非常复杂,实际上用这些方块已经能弄出很多图形了……首先一个显然的结论是奇数个1不可能完成,以下讨论均默认偶数个1。
考虑我们用一个T形的和一个Z形的即可构出如下的反转方案
100
100
同样,用一个L形的和一个Z形的即可构出如下的反转方案
010
100
也就是说,如果不考虑边界,我们可以把一个1直接挪到它的八个邻点之一。理论上如果边界无限远则任意一种局面都可行。考虑边界是怎样的,不妨设n<=m,易证如果n>=2并且m>=3就一定可以。考虑更小的边界,对于2×2的暴力判一下即可。剩下的,对于n=1的情况手动用I形的覆盖一下即可……
#include
#include
#define N 10000005
using namespace std;
namespace runzhe2000
{
int read01(){char c = getchar(); for(; c != '0' && c != '1'; c = getchar()); return c - '0';}
int a[N], n, m, T;
void main()
{
scanf("%d",&T);
for(; T--; )
{
int cnt = 0, siz = 0; scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) cnt += (a[++siz] = read01());
if(cnt&1) puts("No");
else
{
if((n>=2 && m>=3) || (m>=2 && n>=3)) puts("Yes");
else if(n == 2 && m == 2) puts((cnt&&cnt!=4)?"No":"Yes");
else
{
n > m ? m = n: 0;
if(m <= 3) puts(cnt?"No":"Yes");
else
{
for(int i = 1, ii = m-3; i <= ii; i++)
if(a[i])
{
cnt -= a[i] + a[i+1] + a[i+2] + a[i+3];
a[i] ^= 1; a[i+1] ^= 1; a[i+2] ^= 1; a[i+3] ^= 1;
cnt += a[i] + a[i+1] + a[i+2] + a[i+3];
}
puts(cnt?"No":"Yes");
}
}
}
}
}
}
int main()
{
runzhe2000::main();
}
考虑已经知道区间[l,r]的答案,现在在r后面加入a[i] (r+1=i),区间[l,i]的答案会变成什么。记区间[l,r]的答案为sum,c表示[l,r]里面比a[i]小的数的个数,s表示[l,r]里面比a[i]大的数的和,则推一下发现[l,i]的答案是 sum+(c+1)*a[i]+s。
推广下去,考虑已经知道了区间[l,r]以及其所有子区间的答案,同样加入一个a[i],考虑区间[l,i]以及其所有子区间的答案会变成什么。同样推一下得到答案是: sum+∑a[j]>a[i]j∗a[j]+(∑a[k]<a[i]k+i)∗a[i]
实际上并不一定要严格小于或大于,a相等的随便归到其中一类就行了。分别维护式子后两项两个求和即可。
这个东西线段树和平衡树都可以做,然而我好久没碰平衡树了,因此写了一发splay,怒卡了3波常数才过???(大概不作死就不会死)
还垫底了- -
#include
#define N 1000005
#define MOD 1000000007
using namespace std;
namespace runzhe2000
{
typedef long long ll;
const int INF = 1<<30;
int happy, n, a[N], A, B, C;
struct node
{
node *ch[2], *fa;
int v, v1, v2, sum1, sum2;
}mem[N], *tot, *null, *root;
node* newnode(){node *p = ++tot; *p = *null; return p;}
void init()
{
null = tot = mem; null->ch[0] = null->ch[1] = null->fa = null;
null->v1 = null->v2 = null->sum1 = null->sum2 = 0;
node *p = newnode(); p->v = -INF; root = newnode(); root->v = INF;
p->fa = root, root->ch[0] = p;
}
int type(node *x){return x->fa->ch[1]==x;}
void pushup(node *x)
{
x->sum1 = ((x->v1 + x->ch[0]->sum1)%MOD + x->ch[1]->sum1)%MOD;
x->sum2 = ((x->v2 + x->ch[0]->sum2)%MOD + x->ch[1]->sum2)%MOD;
}
void rotate(node *x)
{
node *f = x->fa; int d = type(x);
(x->fa = f->fa) != null ? x->fa->ch[type(f)] = x : 0;
(f->ch[d] = x->ch[!d]) != null ? f->ch[d]->fa = f : 0;
x->ch[!d] = f, f->fa = x; pushup(f);
}
void splay(node *x)
{
for(; x->fa != null; )
{
if(x->fa->fa == null) rotate(x);
else if(type(x->fa) == type(x)) rotate(x->fa), rotate(x);
else rotate(x), rotate(x);
}
pushup(root = x);
}
void insert(node *x, node *f, node *p, int t)
{
if(x == null){p->fa = f; f->ch[t] = p; return;}
if(x->v <= p->v) insert(x->ch[1], x, p, 1);
else insert(x->ch[0], x, p, 0); pushup(x);
}
void main()
{
happy = scanf("%d%d%d%d%d",&n,&a[1],&A,&B,&C);
init(); ll ans = 0, sum = 0;
for(int i = 2; i <= n; i++) a[i] = ((ll)a[i-1] * A + B) % C;
for(int i = 1; i <= n; i++)
{
node *x = newnode(); x->v = a[i], x->v1 = (ll)i*a[i]%MOD, x->v2 = i;
insert(root, null, x, 0); splay(x);
sum = (sum + root->ch[1]->sum1 + (ll)(root->ch[0]->sum2 + i) * a[i] % MOD ) % MOD;
(ans += sum) %= MOD;
}
printf("%lld\n",ans);
}
}
int main()
{
runzhe2000::main();
}
我们考虑所有黑点与点x的LCA之和等于什么,就等于:x子树内的黑点个数 * x + x的所有祖先f的子树内的所有不在x到f的路径上的黑点个数*f
前者就直接用一个线段树搞一搞。
对于后者,其实就是根到x的一个链上信息,考虑LCT。列了一下大概要差不多十种标记才能维护清楚这个东西(还不知道有没有想错,代码能力太弱果断弃)……既然LCT似乎能做,考虑树剖?把这条链拆成若干重链,对每一条重链维护信息,重链交接的地方单独做一下即可。同样上一颗线段树维护即可, O(mlog2n) 。
做法口胡完了QAQ。实际上对于后者,要维护的信息还是很多,比如轻边的子树内黑点个数,区间奇数层取反完值会变化多少等等……
不得不说51Nod的评测机是真的快,本机极限数据跑了差不多10s,我还他以为卡两个log。正在绝望之际,交一发,1.5s就过出来了……其实大概是本机太慢了吧,这个电脑连打字都越来越卡了……
#include
#define N 200005
using namespace std;
namespace runzhe2000
{
typedef long long ll;
int read()
{
int r = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar());
for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
return r;
}
int n, m, last[N], ecnt, c[N], top[N], siz[N], fa[N], son[N], dep[N], beg[N], rebeg[N], end[N], timer;
struct edge{int next, to;}e[N<<1];
void addedge(int a, int b){e[++ecnt] = (edge){last[a], b}; last[a] = ecnt;}
void dfs1(int x)
{
dep[x] = dep[fa[x]] + 1; siz[x] = 1; for(int i = last[x]; i; i = e[i].next)
{int y = e[i].to; if(y == fa[x]) continue;fa[y] = x; dfs1(y); siz[x] += siz[y]; siz[y] > siz[son[x]] ? son[x] = y : 0;}
}
void dfs2(int x)
{
rebeg[beg[x] = ++timer] = x; top[x] = son[fa[x]]==x?top[fa[x]]:x; if(son[x]) dfs2(son[x]);
for(int i = last[x]; i; i = e[i].next){int y = e[i].to; if(y == son[x] || y == fa[x]) continue;dfs2(y);}end[x] = timer;
}
struct seg
{
int siz[2], siz_bla[2], rev[2]; ll mod[2], val;
}t1[N*5], t2[N*5];
/***************************************************************************************************************/
void pushup1(int x)
{
seg *ls = &t1[x<<1], *rs = &t1[x<<1|1];
for(int i = 0; i != 2; i++)
{
t1[x].siz[i] = ls->siz[i] + rs->siz[i];
t1[x].siz_bla[i] = ls->siz_bla[i] + rs->siz_bla[i];
}
}
void pushdown1(int x)
{
seg *ls = &t1[x<<1], *rs = &t1[x<<1|1];
for(int i = 0; i != 2; i++) if(t1[x].rev[i])
{
ls->siz_bla[i] = ls->siz[i] - ls->siz_bla[i], rs->siz_bla[i] = rs->siz[i] - rs->siz_bla[i];
ls->rev[i] ^= 1, rs->rev[i] ^= 1, t1[x].rev[i] = 0;
}
}
void build1(int x, int l, int r)
{
t1[x].rev[0] = t1[x].rev[1] = 0;
if(l == r)
{
int id = rebeg[l], d = (dep[id]&1);
t1[x].siz[d] = 1; t1[x].siz[!d] = 0;
t1[x].siz_bla[d] = c[id]; t1[x].siz_bla[!d] = 0;
return;
}
int mid = (l+r)>>1; build1(x<<1,l,mid); build1(x<<1|1,mid+1,r); pushup1(x);
}
int query1_siz_bla(int x, int l, int r, int ql, int qr, int d)
{
if(ql <= l && r <= qr) return t1[x].siz_bla[d]; int mid = (l+r)>>1, ret = 0; pushdown1(x);
if(ql <= mid) ret += query1_siz_bla(x<<1,l,mid,ql,qr,d); if(mid1|1,mid+1,r,ql,qr,d); return ret;
}
int query1_siz_bla(int x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return t1[x].siz_bla[0]+t1[x].siz_bla[1]; int mid = (l+r)>>1, ret = 0; pushdown1(x);
if(ql <= mid) ret += query1_siz_bla(x<<1,l,mid,ql,qr); if(mid1|1,mid+1,r,ql,qr); return ret;
}
int query1_siz(int x, int l, int r, int ql, int qr, int d)
{
if(ql <= l && r <= qr) return t1[x].siz[d]; int mid = (l+r)>>1, ret = 0; pushdown1(x);
if(ql <= mid) ret += query1_siz(x<<1,l,mid,ql,qr,d); if(mid1|1,mid+1,r,ql,qr,d); return ret;
}
void modi1(int x, int l, int r, int ql, int qr, int d)
{
if(ql <= l && r <= qr) {t1[x].rev[d] ^= 1; t1[x].siz_bla[d] = t1[x].siz[d] - t1[x].siz_bla[d]; return;} int mid = (l+r)>>1;
pushdown1(x); if(ql <= mid) modi1(x<<1,l,mid,ql,qr,d); if(mid < qr) modi1(x<<1|1,mid+1,r,ql,qr,d); pushup1(x);
}
/***************************************************************************************************************/
void pushup2(int x)
{
seg *ls = &t2[x<<1], *rs = &t2[x<<1|1];
for(int i = 0; i != 2; i++)
{
t2[x].siz[i] = ls->siz[i] + rs->siz[i];
t2[x].siz_bla[i] = ls->siz_bla[i] + rs->siz_bla[i];
t2[x].mod[i] = ls->mod[i] + rs->mod[i];
t2[x].val = ls->val + rs->val;
}
}
void pushdown2(int x)
{
seg *ls = &t2[x<<1], *rs = &t2[x<<1|1];
for(int i = 0; i != 2; i++) if(t2[x].rev[i])
{
ls->siz_bla[i] = ls->siz[i] - ls->siz_bla[i], rs->siz_bla[i] = rs->siz[i] - rs->siz_bla[i];
ls->rev[i] ^= 1, rs->rev[i] ^= 1, t2[x].rev[i] = 0;
ls->val += ls->mod[i], rs->val += rs->mod[i];
ls->mod[i] *= -1, rs->mod[i] *= -1;
}
}
void build2(int x, int l, int r)
{
t2[x].rev[0] = t2[x].rev[1] = 0;
if(l == r)
{
int id = rebeg[l], d = (dep[id]&1);
t2[x].siz[d] = 1; t2[x].siz[!d] = 0;
t2[x].siz_bla[d] = query1_siz_bla(1,1,n,beg[id],beg[id]);
t2[x].siz_bla[!d] = 0;
for(int i = last[id]; i; i = e[i].next)
{
int y = e[i].to; if(y == son[id] || y == fa[id]) continue;
t2[x].siz[d] += query1_siz(1,1,n,beg[y],end[y],d);
t2[x].siz[!d] += query1_siz(1,1,n,beg[y],end[y],!d);
t2[x].siz_bla[d] += query1_siz_bla(1,1,n,beg[y],end[y],d);
t2[x].siz_bla[!d] += query1_siz_bla(1,1,n,beg[y],end[y],!d);
}
t2[x].mod[d] = (t2[x].siz[d] - 2ll * t2[x].siz_bla[d]) * id;
t2[x].mod[!d] = (t2[x].siz[!d] - 2ll * t2[x].siz_bla[!d]) * id;
t2[x].val = (ll)(t2[x].siz_bla[d] + t2[x].siz_bla[!d]) * id;
return;
}
int mid = (l+r)>>1; build2(x<<1,l,mid); build2(x<<1|1,mid+1,r); pushup2(x);
}
ll query2(int x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return t2[x].val; int mid = (l+r)>>1; ll ret = 0; pushdown2(x);
if(ql <= mid) ret += query2(x<<1,l,mid,ql,qr); if(mid < qr) ret += query2(x<<1|1,mid+1,r,ql,qr); return ret;
}
void modi2(int x, int l, int r, int ql, int qr, int d)
{
if(ql <= l && r <= qr)
{
t2[x].siz_bla[d] = t2[x].siz[d] - t2[x].siz_bla[d];
t2[x].rev[d] ^= 1;
t2[x].val += t2[x].mod[d];
t2[x].mod[d] *= -1;
return;
}
int mid = (l+r)>>1; pushdown2(x);
if(ql <= mid) modi2(x<<1,l,mid,ql,qr,d); if(mid < qr) modi2(x<<1|1,mid+1,r,ql,qr,d); pushup2(x);
}
void update2(int x, int l, int r, int p)
{
if(l == r) {build2(x,l,r); return;} int mid = (l+r)>>1; pushdown2(x);
if(p <= mid) update2(x<<1,l,mid,p); else update2(x<<1|1,mid+1,r,p); pushup2(x);
}
/***************************************************************************************************************/
void main()
{
n = read(), m = read();
for(int i = 1; i <= n; i++) c[i] = read();
for(int i = 1, a, b; i < n; i++)
addedge(a = read(), b = read()), addedge(b,a);
dfs1(1); dfs2(1); build1(1,1,n); build2(1,1,n);
for(int t = 1, op, x; t <= m; t++)
{
op = read(), x = read();
if(op == 1)
{
int d = (dep[x]&1)^1;
modi1(1,1,n,beg[x],end[x],d);
for(int tmp = top[x]; fa[tmp]; tmp = top[fa[tmp]]) update2(1,1,n,beg[fa[tmp]]);
modi2(1,1,n,beg[x],end[x],d);
}
else if(op == 2)
{
int d = (dep[x]&1);
modi1(1,1,n,beg[x],beg[x],d); update2(1,1,n,beg[x]);
for(int tmp = top[x]; fa[tmp]; tmp = top[fa[tmp]]) update2(1,1,n,beg[fa[tmp]]);
}
else
{
ll ans = (ll)x * query1_siz_bla(1,1,n,beg[x],end[x]);
for(int tmp = x, son = x; tmp; tmp = fa[son = top[tmp]])
{
if(tmp != x) ans += (ll)tmp * (query1_siz_bla(1,1,n,beg[tmp],end[tmp]) - query1_siz_bla(1,1,n,beg[son],end[son]));
if(tmp != top[tmp]) ans += query2(1,1,n,beg[top[tmp]],beg[tmp]-1);
}
printf("%lld\n",ans);
}
}
}
}
int main()
{
runzhe2000::main();
}