【洛谷】xht膜你赛 题解

前言

大家期待已久并没有的题解终于来啦~ 这次的T1和HAOI2016撞题了…深表歉意…表示自己真的不知情…

天下的水题总是水得相似,神题各有各的神法。——《安娜·卡列妮娜》

出题的过程:@PhoenixEclipse @xht13127提供了一些想法,我负责写标程,对拍,造数据…然后@SakuraDance帮我验了题。感谢上述,以及其他几位dalao的资辞。

题解

T1

和HAOI2016撞车 http://www.lydsy.com/JudgeOnline/PRoblem.php?id=4562

30分做法:直接爆搜,注意取模。

100分做法:topo排序然后简单dp,或者直接爆搜加个记忆化…(如果是记忆化,记得不要用0来表示未访问的点QwQ)

T2

一道披着几何外衣的数学题~

问题可以转化为,对 a≤i≤b ,所有 xyz=i 的所有整数解(x,y,z) , 求(|x|+|y|+|z|)2 的和。

由于对称性,所以我们只需要算第一卦限(x,y,z>0)的答案,再乘4就行啦。

30分做法:暴力枚举i,再暴力枚举满足xyz=ix,y,z,然后暴力计算答案。

60分做法

首先,我们可以用[1,b] 的答案减去 [1,a−1] 的答案。

然后注意到(x+y+z)2=(x2+y2+z2)+2(xy+yz+zx) , 其中两个括号里的三项都是对称式。于是我们可以单独算出所有的x2yz 对答案的贡献,再把前者加上后者乘2。

接下来推式子…公式恐惧症请做好心理准备

σ(n) 等于n的约数个数; ans1=====∑i=1N∑xyz=ix2∑i=1N∑x|ix2∑yz=ix∑i=1N∑x|ix2σ(ix)∑x=1Nx2∑x|iσ(ix)∑x=1Nx2∑d≤⌊N/x⌋σ(d)

ans2=====∑i=1N∑xyz=iyz∑i=1N∑x|i∑yz=ixyz∑i=1N∑x|iixσ(ix)∑i=1N∑x|ixσ(x)∑x=1Nxσ(x)⌊Nx⌋

ans=4∗(ans1+2∗ans2)

对于ans1,因为⌊Nx⌋ 只有N−−√ 种取值, 我们可以用一种经典的方法分段计算,再对后面的前缀和预处理出来,或者暴力求和,这样可以做到O(N)。

对于ans2,同样分段计算,再预处理xσ(x) 的前缀和,也是O(N)。 总复杂度:O(N)。如果你喜欢用一种NlgN的方法筛约数个数…那就是O(NlgN)。

现场有一位大爷用了筛法也过了60分,orz。

100分做法

在60分做法的基础上,用杜教筛求σ(x)xσ(x) 的前缀和,复杂度O(N^(2/3))。 详见唐老师博客:http://blog.****.net/skywalkert/article/details/50500009

T3

被喷是裸的数据结构题了啊

观察题目中的要求,将变量看做点,方程看做边,只会形成一棵树。

30分做法:因为只有询问操作,我们先读入所有数据,建一棵树,每条边用两条有向边表示,权值分别为c和-c,然后dfs一遍,预处理出lca(或者你要树剖也行),然后处理询问。

100分做法:发现只要用LCT维护就行了。几个细节:边权不好维护,那么我们就插入虚拟的点来表示边。在询问一条链的时候,要求链上的方程是x1-x2=a, x2-x3=b, x3-x4=c…这样的形式,即要求符号的方向相同。我们可以让每条边上的方程表示子节点减父节点的值,然后换根的时候,发现只有新的根到原来的根的路径上的顺序要颠倒,于是在access的splaytree里面打一个tag取反。具体实现见代码。

代码

T1

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=1e5+5, MD=10007; int in[MAXN], deg[MAXN], to[MAXN][10], K[MAXN], N; int p[MAXN], M, f[MAXN], ans; int read() { int r=0, c=getchar(); while(c<'0'||'9'<c) c=getchar(); while('0'<=c&&c<='9') r=r*10+c-'0', c=getchar(); return r; } int main() { scanf("%d", &N); for(int i=1; i<=N; ++i){ K[i]=read(); for(int j=0; j<K[i]; ++j) in[to[i][j]=read()]++; } for(int i=1; i<=N; ++i) if(!in[i]) f[p[M++]=i]=1; for(int i=0; i<M; ++i){ int u=p[i]; for(int j=0; j<K[u]; ++j){ int v=to[u][j]; if(!(--in[v])) p[M++]=v; } } for(int i=0; i<M; ++i){ int u=p[i]; for(int j=0; j<K[u]; ++j){ int v=to[u][j]; f[v]=(f[v]+f[u])%MD; } if(!K[u]) ans=(ans+f[u])%MD; } printf("%d\n", ans); return 0; }

T2

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 5e6+5, MD=10007; int pr[MAXN], f[MAXN], g[MAXN], np, M; short ip[MAXN]; void pre() { ip[1]=f[1]=1; for(int i=2; i<M; ++i){ if(!ip[i]) pr[np++]=i, f[i]=2, g[i]=1; for(int j=0, k, p; j<np; ++j){ p=pr[j], k=i*p; if(k>=M) break; ip[k]=1; if(i%p==0){ f[k]=f[i]/(g[i]+1)*(g[i]+2); g[k]=g[i]+1; break; } f[k]=f[i]*2; g[k]=1; } } for(int i=1; i<M; ++i){ f[i]%=MD; g[i]=(i*f[i]+g[i-1])%MD; f[i]=(f[i]+f[i-1])%MD; } } int F(int n) { if(n<M) return f[n]; int r=0; for(int i=1, j; i<=n; i=j+1){ int t=n/i; j=n/t; r=(r+(ll)(j-i+1)*t)%MD; } return r; } int G(int n) { if(n<M) return g[n]; int r=0; for(int i=1, j; i<=n; i=j+1){ int t=n/i; j=n/t; r=(r+((ll)(i+j)*(j-i+1)/2%MD)*t*(t+1)/2)%MD; } return r; } int work(int n) { int l=0, c=0, r1=0, r2=0; for(ll i=1, j; i<=n; i=j+1){ j=n/(n/i); c=(ll)j*(j+1)%MD*(2*j+1)*1668%MD; r1=(r1+(ll)(c-l+MD)*F(n/i))%MD; l=c; } l=0; for(ll i=1, j; i<=n; i=j+1){ j=n/(n/i); c=G(j); r2=(r2+(ll)(c-l+MD)*(n/i))%MD; l=c; } return (r1+r2*2)*12%MD; } int main() { int a, b; scanf("%d%d", &a, &b); for(M=0; M*M*M<=b; M++); M=min(MAXN, M*M); pre(); printf("%d\n", (work(b)-work(a-1)+MD)%MD); return 0; }

T3

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 3e5+5, MD=6662333; struct Node { Node *ch[2], *fa; int rev, inv, w, sum; }tr[MAXN], *nil=tr; inline void init(int x) { tr[x].ch[0]=tr[x].ch[1]=tr[x].fa=nil; } inline void up(Node *x) { Node *l=x->ch[0], *r=x->ch[1]; x->sum=x->w+l->sum+r->sum; } inline void down(Node *x) { Node *l=x->ch[0], *r=x->ch[1]; if(x->inv){ l->inv^=1; l->sum=-l->sum; l->w=-l->w; r->inv^=1; r->sum=-r->sum; r->w=-r->w; x->inv=0; } if(x->rev){ l->rev^=1; r->rev^=1; swap(x->ch[0], x->ch[1]); x->rev=0; } } inline int isrt(Node *x){return !(x->fa->ch[0]==x||x->fa->ch[1]==x);} void rot(Node *x) { Node *y=x->fa, *z=y->fa; int l=y->ch[1]==x, r=!l; if(!isrt(y)) z->ch[z->ch[1]==y]=x; x->ch[r]->fa=y; y->fa=x; x->fa=z; y->ch[l]=x->ch[r]; x->ch[r]=y; up(y); up(x); } Node *st[MAXN]; int top; void splay(Node *x) { st[top=0]=x; for(Node *u=x; !isrt(u); u=u->fa) st[++top]=u->fa; while(top>=0) down(st[top--]); while(!isrt(x)){ Node *y=x->fa, *z=y->fa; if(!isrt(y)) rot((z->ch[1]==y)^(y->ch[1]==x)?x:y); rot(x); } } void access(Node *x) { for(Node *t=nil; x!=nil; t=x, x=x->fa) splay(x), x->ch[1]=t, up(x); } void mkrt(Node *x) { access(x); splay(x); x->rev^=1; x->inv^=1; x->sum=-x->sum; x->w=-x->w; } void lnk(Node *x, Node *y) { mkrt(x); x->fa=y; } void cut(Node *x, Node *y) { mkrt(x); access(y); splay(y); x->fa=y->ch[0]=nil; } Node *getrt(Node *x) { while(x->fa!=nil) x=x->fa; return x; } int N, M, K, Q, ne; inline int xht(int x){return x>0?x%K:(K-(-x)%K)%K;} int ha[MAXN], hb[MAXN], he[MAXN], nxt[MAXN], hd[MD], nh=1; void add(int a, int b, int e) { int k=((ll)a*b+a+b)%MD; ha[nh]=a; hb[nh]=b; he[nh]=e; nxt[nh]=hd[k]; hd[k]=nh++; } int del(int a, int b) { int k=((ll)a*b+a+b)%MD; for(int i=hd[k], j=0; i; i=nxt[i], j=i){ if((ha[i]==a&&hb[i]==b)||(ha[i]==a&&hb[i]==b)){ if(!j) hd[k]=nxt[i]; else nxt[j]=nxt[i]; return he[i]; } } return 0; } int main() { scanf("%d%d%d%d", &N, &M, &K, &Q); ne=N+1; for(int i=0; i<=N+M+Q; ++i) init(i); for(int i=0; i<M; ++i){ int a, b, c; scanf("%d%d%d", &a, &b, &c); // G[a][b]=G[b][a]=ne; add(a, b, ne); tr[ne].w=tr[ne].sum=c; lnk(tr+a, tr+ne); lnk(tr+ne, tr+b); ne++; } for(int i=0; i<Q; ++i){ int t, a, b, c; scanf("%d%d%d", &t, &a, &b); if(t==1){ scanf("%d", &c); // G[a][b]=G[b][a]=ne; add(a, b, ne); tr[ne].w=tr[ne].sum=c; lnk(tr+a, tr+ne); lnk(tr+ne, tr+b); ne++; }else if(t==2){ // int e=G[a][b]; int e=del(a, b); if(e){ cut(tr+a, tr+e); cut(tr+e, tr+b); // G[a][b]=G[b][a]=0; } }else{ scanf("%d", &c); if(getrt(tr+a)==getrt(tr+b)){ mkrt(tr+a); access(tr+b); splay(tr+b); printf("%d\n", xht(c-tr[b].sum)); }else puts("-1"); } } return 0; }