ZJOI没过几天:
教练:明天我们做ZJOI.
众人:那我怕是要爆零了
wxh:(冒金光)
教练:这次ZJOI很难,全场最高130。
众人:那我怕是连10分都没了
wxh:(冒金光)
第二天:
mcfx:(开场做t1)
wxh:(30min后开始写代码)
我:???
(2h后)
mcfx:(还在写t1)
wxh:(拿起水杯走出了机房,电脑上显示FC:找不到差异)
我:???
mcfx:我去改改FLOJ把wxh标成金光怎么样?(20min后)改好了
我:这个好,要不要加个atcoder的皇冠上去
wxh:(冒金光)
(3h后)
mcfx:(还在写t1,已经4k了)
wxh:(写了一会代码就趴在桌上)
我:(终于会t2暴力了)
(4h后)
mcfx:(还在写t1)
wxh:(观看mcfx写t1)
我:怎么这个大样例还没过
(过了一会)
mcfx:我这个写不完了
wxh:我发现t3部分分有规律
owenowl:t1 50真好拿
我:(刚过了t2,是推T1还是看t3规律呢?算了,我选择去找规律)
(结束时)
mcfx:又水了一场比赛,得分0
wxh:(冒金光)
我:woc t1 50分那么sb(t3没发现任何规律,得分0)
(下午讲评时)
wxh:t2傻逼题你们怎么不会啊
众人:wxh赛高!wxh冒金光!
早知道看t1时应该顺便推一下部分分。。。整个机房一堆人50分
结果5h用了4h做t2,最后没时间推t1了,110滚粗(现场赛有debuff分数肯定比这个低),然后那个冒金光的wxh 2h秒了t2,最后得分190
ZJOI2018 Problem B.历史
想了半天这个序列应该有啥性质,后来才发现应该对每个点考虑。这样就简单多了,对于每个点,答案就是 ∑sum[u]−1−max(0,mx[u]−1−(sum[u]−mx[u])) ( sum[u]=∑v在u的子树里a[u],mx[u]=maxv在u的子树里(a[u]) ),即把一堆点硬点一个顺序,尽量使相邻编号不一样的对数最多。显然直接考虑往出现次数最多的点的空隙里面丢。
化一下可以发现是满足
2∗mx≥sum[u]+1
时会有特殊贡献
2∗(sum[u]−mx)
,否则就是
sum[u]−1
(其实我觉得第一步最难,后面好像挺简单的。。。)
发现这个东西很像树剖,假设把 mx 当成重儿子,那么从一个叶子到根最多只会经过 O(log∑a[i]) 条轻链,所以用LCT来暴力维护,至于复杂度应该也不会高。。。
#include<bits/stdc++.h>
#define maxn 401000
#define LLD "%lld"
using namespace std;
typedef long long ll;
int ch[maxn][2],fa[maxn],pa[maxn],n,Q;
ll atg[maxn],val[maxn],ans,dp[maxn],a[maxn],son[maxn];
vector<int>G[maxn];
void addedge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
typedef pair<ll,int> par;
void dfs(int u){
dp[u]=a[u];
par mx=par(a[u],u);
for(int i=0,p;i<G[u].size();++i)if((p=G[u][i])!=pa[u])
pa[p]=u,dfs(p),mx=max(mx,par(dp[p],p)),dp[u]+=dp[p],fa[p]=u;
if(mx.first*2>dp[u]+1){
son[u]=mx.second;
if(son[u]!=u)ch[u][1]=son[u];
ans+=val[u]=2*(dp[u]-mx.first);
} else ans+=val[u]=dp[u]-1;
}
int isroot(int x){
if(!x||!fa[x])return 1;
return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
}
void rotate(int p){
int q=fa[p],y=fa[q],k=(ch[q][1]==p);
if(!isroot(q))ch[y][ch[y][1]==q]=p;
fa[ch[q][k]=ch[p][k^1]]=q;
fa[ch[p][k^1]=q]=p;
fa[p]=y;
}
void pd(int p){
if(!p)return ;
if(atg[p]){
if(ch[p][0])atg[ch[p][0]]+=atg[p],dp[ch[p][0]]+=atg[p];
if(ch[p][1])atg[ch[p][1]]+=atg[p],dp[ch[p][1]]+=atg[p];
atg[p]=0;
}
}
void splay(int x){
static int sta[maxn];
int tp=0;
for(int y=x;!isroot(y);y=fa[y])sta[++tp]=y;
while(tp)pd(sta[tp--]);
while(!isroot(x)){
int y=fa[x];
if(!isroot(y)){
if((ch[fa[y]][1]==y)^(ch[y][1]==x))rotate(x);
else rotate(y);
}
rotate(x);
}
pd(x);
}
int gettop(int x){
while(ch[x][0])x=ch[x][0];
splay(x);
return x;
}
ll find(int z){
splay(z);
return dp[z];
}
void access(int x,ll add){
a[x]+=add;
int X=x,y=x;
for(;x;x=fa[x]){
splay(x);
dp[x]+=add;
dp[ch[x][0]]+=add;
atg[ch[x][0]]+=add;
}
x=X,splay(x);
if(a[x]*2>dp[x]+1){
son[x]=x;
ans-=val[x];
val[x]=2*(dp[x]-a[x]);
ans+=val[x];
ch[x][1]=0;
} else {
if(son[x]){
ll mx=(son[x]==x?a[x]:find(son[x]));
splay(x);
if(mx*2<=dp[x]+1){
ans-=val[x];
val[x]=dp[x]-1;
ans+=val[x];
son[x]=0;
ch[x][1]=0;
} else ans+=2*add,val[x]+=add*2;
} else ans+=add,val[x]+=add;
}
y=gettop(x);
while(pa[y]){
splay(pa[y]);
int z=pa[y];
if(dp[y]*2>dp[z]+1){
ans-=val[z];
val[z]=2*(dp[z]-dp[y]);
ans+=val[z];
ch[z][1]=y;
son[z]=y;
} else {
if(son[z]){
ll mx=(son[z]==z?a[z]:find(son[z]));
splay(z);
if(mx*2<=dp[z]+1){
ans-=val[z];
val[z]=dp[z]-1;
ans+=val[z];
son[z]=0;
ch[z][1]=0;
} else ans+=2*add,val[z]+=2*add;
} else ans+=add,val[z]+=add;
}
splay(z);
y=gettop(z);
}
}
int main(){
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;++i)scanf(LLD,&a[i]);
for(int i=2,u,v;i<=n;++i)scanf("%d%d",&u,&v),addedge(u,v);
dfs(1);
printf(LLD"\n",ans);
while(Q--){
int A,w;
scanf("%d%d",&A,&w);
access(A,w);
printf(LLD"\n",ans);
}
}
ZJOI2018 Problem C.迷宫
看见这题完全没思路,还跑去找规律,然后没发现任何规律。。。
显然有一个答案上界
K
,即建一些点分别代表余数为
现在,我们手上有
1...K−1
,
0
早就消失了。把这些数都乘上
令
令
如果
d=1
,那么所有数都代表不同的类,答案为
L
如果
这个时候,上一层算出的等价类为
(L,K)
,由于多了一层相当于多了
m
个选择,所以这一层已经被删除了
至于为什么要用__int128,显然是因为没判区间是否为空,这样会算出负数导致爆ll,判了就不用__int128了。
#include<bits/stdc++.h>
#define D "%lld"
using namespace std;
typedef long long ll;
long long m,K,T;
ll sol(ll L,ll K){
ll d=__gcd(m,K);
if(d==1||L<=K/d)return L;
if((K-L)>K/m)return K/d;
return m/d*(K-L)+sol(K/d-m/d*(K-L),K/d);
}
int main(){
scanf(D,&T);
while(T--){
scanf(D D,&m,&K);
printf(D "\n",sol(K-1,K)+1);
}
}
ZJOI2018 Problem A.线图 题解?不存在的,自己看jiry题解。再见
#include<bits/stdc++.h>
#define mod 998244353
#define maxn 5010
#define maxm 100100
#define _c2(x) (1ll*(x)*((x)-1)/2)
#define pf(x) (1ll*(x)*(x))
using namespace std;
typedef pair<int,int> par;
int ans,anses[1<<20],E[maxn][22],K,n,pd[30][30];
int dgr[maxm],dgsum[maxm],dgsqr[maxm],fa[maxn],dp[maxn][20],P[2][1<<11];
vector<int>G[maxn],T[maxn];
vector<par>B[maxm],C;
void addedge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
int cal(int n,int m,int K){
if(K==1)return m;
for(int i=1;i<=n;++i)dgr[i]=dgsum[i]=dgsqr[i]=0;
for(auto p:C)dgr[p.first]++,dgr[p.second]++;
if(K==2){
int ans=0;
for(int i=1;i<=n;++i)
ans=(ans+_c2(dgr[i]))%mod;
return ans;
} else if(K==3){
int ans=0;
for(auto p:C)ans=(ans+_c2(dgr[p.first]+dgr[p.second]-2))%mod;
return ans;
} else if(K==4){
int ans=0;
for(auto p:C){
int X=dgr[p.first]+dgr[p.second]-2;
dgsqr[p.first]=(dgsqr[p.first]+pf(X))%mod;
dgsqr[p.second]=(dgsqr[p.second]+pf(X))%mod;
dgsum[p.first]=(dgsum[p.first]+X)%mod;
dgsum[p.second]=(dgsum[p.second]+X)%mod;
}
for(int i=1;i<=n;++i){
int sqr=dgsqr[i],sum=dgsum[i],dg=dgr[i];
ans=(ans+1ll*sum*sum-sqr+1ll*(dg-1)*sqr-5ll*(dg-1)*sum+6ll*_c2(dg))%mod;
}
return 1ll*ans*(mod+1)/2%mod;
} else {
int id=0,cnt=0;
for(int i=1;i<=n;++i)B[i].clear();
for(auto p:C)
B[p.first].push_back(par(p.second,++cnt)),
B[p.second].push_back(par(p.first,cnt));
C.clear();
for(int i=1;i<=n;++i)
for(int j=0;j<B[i].size();++j)
for(int k=0;k<j;++k)
C.push_back(par(B[i][j].second,B[i][k].second));
return cal(m,C.size(),K-1);
}
}
int build(string tree,int K,int& cnt){
int rt=1,id=1;
for(int i=0;i<tree.length();++i){
if(tree[i]=='0'){
rt=fa[rt];
} else {
T[rt].push_back(++id);
T[id].push_back(rt);
C.push_back(par(rt,id));
fa[id]=rt,rt=id;
}
if(!rt)return -1;
else if(id>K)return -1;
}
return id;
}
string gethash(int rt,int S,int f){
vector<string> v;
for(auto p:T[rt])if(p!=f&&(S>>p-1&1))
v.push_back(gethash(p,S,rt));
sort(v.begin(),v.end());
string ret="";
for(auto p:v)ret+="1"+p+"0";
return ret;
}
int zip(string s){
int S=1;
for(int i=0;i<s.length();++i)S=S<<1|(s[i]=='1');
return S;
}
int getdp(int u,int f,int K){
for(int i=1;i<=K;++i)dp[u][i]=0;
for(auto p:G[u])if(p!=f)
getdp(p,u,K);
for(int i=1;i<=K;++i){
int flg=0;
for(int j=1;j<i;++j)if(pd[i][j])
dp[u][i]=dp[u][j],flg=1;
if(flg)continue;
int cnt=0;
vector<int>L;
L.clear();
for(auto p:T[i])if(p!=fa[i])
T[p].size()==1?cnt++:(L.push_back(p),0);
if(L.size()+cnt>G[u].size()-(f!=0))continue;
int S=1<<L.size(),p=0,np=1;
for(int j=0;j<S;++j)P[0][j]=P[1][j]=0;
P[np][0]=1;
for(auto v:G[u])if(v!=f){
for(int j=0,ns=0;j<L.size();++j,ns=0)if(dp[v][L[j]]){
for(int k=0;k<j;++k)if(pd[L[k]][L[j]])ns|=1<<k;
for(int k=(S-1)^ns^(1<<j),D=(S-1)^ns^(1<<j);;k=(k-1)&D){
if(!P[np][k|ns]){
if(!k)break;
else continue;
}
P[p][k|(1<<j)|ns]=(P[p][k|(1<<j)|ns]+1ll*P[np][k|ns]*dp[v][L[j]])%mod;
if(!k)break;
}
}
for(int j=0;j<S;++j)
if(P[np][j])P[p][j]=(P[p][j]+P[np][j])%mod,P[np][j]=0;
swap(p,np);
}
dp[u][i]=1ll*E[G[u].size()-L.size()-(f!=0)][cnt]*P[np][S-1]%mod;
}
}
typedef unsigned long long ull;
map<ull,int>mp;
ull _gethash2(int n){
ull ret=0;
vector<int>v;
for(int i=1;i<=n;++i)v.push_back(zip(gethash(i,(1<<n)-1,0)));
sort(v.begin(),v.end());
for(int i=0;i<n;++i)ret=ret*19260817+v[i];
return ret;
}
void dfs(string tree,int K,int P){
if(tree.length()==2*(K-1)){
int _cnt=0;
for(int i=1;i<=K;++i)T[i].clear();
C.clear();
if(build(tree,K,_cnt)!=K)return ;
int ss=zip(gethash(1,(1<<K)-1,0));
if(~anses[ss])return ;
anses[ss]=(mp.count(_gethash2(K))?mp[_gethash2(K)]:mp[_gethash2(K)]=cal(K,K-1,P));
for(int i=0;i<(1<<K)-1;++i){
string gt=gethash(__builtin_ctz(i&-i)+1,i,0);
if(gt.length()!=2*(__builtin_popcount(i)-1))continue;
anses[ss]=(anses[ss]-anses[zip(gt)]+mod)%mod;
}
for(int i=1;i<=K;++i)
for(int j=i;j<=K;++j)
pd[i][j]=pd[j][i]=(gethash(i,(1<<K)-1,fa[i])==gethash(j,(1<<K)-1,fa[j]));
getdp(1,0,K);
int val=0;
for(int i=1;i<=n;++i)val=(val+dp[i][1])%mod;
ans=(ans+1ll*anses[ss]*val)%mod;
return ;
}
dfs(tree+"1",K,P);
dfs(tree+"0",K,P);
}
int main(){
// freopen("line.in","r",stdin);
// freopen("line.out","w",stdout);
// freopen("ex_line2.in","r",stdin);
memset(anses,-1,sizeof(anses));
scanf("%d%d",&n,&K);
for(int i=2,u,v;i<=n;++i)
scanf("%d%d",&u,&v),addedge(u,v);
for(int i=0;i<=n;++i)
for(int j=*E[i]=1;j<=i&&j<=20;++j)
E[i][j]=(E[i-1][j]+E[i-1][j-1])%mod;
for(int i=1;i<=K+1;++i)dfs("",i,K);
printf("%d",ans);
}