来了一场既没有$c++11$也没有$O2$的考试。
然后喜闻乐见的出现了一些$CE$,以及被卡常的。
然而与我没有关系,$T1$想到了最高的一档暴力(正解被卡常除外)
然而里面用到了$map$,没$O2$跑的是真的慢,最后拿了个不高不低的$50pts$
然后$T2$是神仙题,$O(n^3)$的$dp$我是天生恐惧。就算改题也是尝试理解了好久。
然后牛一直说它简单,然而给我讲并没有听明白。
哭了,太菜了听啥都像嘲讽。他们不懂底层人民的生活。
虽说我到现在都不明白暴力为什么会挂。
$T3$的最高分$20$居然是信仰的$puts("0")$。数据真神奇,然后还有的人$5pts$思路挺神仙的。。
正解更神仙,完全想不到。
考后改题时间都砸$T2$上了,到处问问了两个半小时只有一个人给我讲,还没讲明白(不敢继续问了23333
后来发现$T1$比较简单就把$T1$弄了下来,然后继续到处问$T2$。很晚很晚才问明白然后$AC$
然后就没时间搞$T3$了。大概思想明白。可以看看$AK$神们的博客。
状态还是很差。快点调整回来啊!!!
T1:space
大意:四维空间,有四个排列$A,B,C,D$。$(i,j,k,l) ightarrow (A_i,B_j,C_k,D_l)$的代价为$1$。其余代价为$2$。求最小代价的经过所有点的回路。$n le 10^5$
排列交换当成建图貌似渐渐成为了套路。?
如果我们对四个维度所有点一起连边,那么最后的代价就是$n^4+$环的个数。
每个四维环都是由四个一维环拼接出来的。改变定义设$A_i$表示大小为$i$的环有多少个。
$ans=n^4+A_iB_jC_kD_lfrac{i,j,k,l}{lcm(i,j,k,l)}$
$A$的数量级别是$O(sqrt{n})$的。所以总复杂度是$O(n^2logn)$的。
然后对前后两个一组分组,$meet in middle$。
大概是个莫反。对于每种质因子考虑可以得到$frac{abcd}{lcm(a,b,c,d)} = gcd(a,b)gcd(c,d)gcd(lcm(a,b),lcm(c,d))$
这样就可以把前后两部分分开。$(A_i,i,B_j,j) ightarrow (A_iB_jgcd(i,j),lcm(i,j))$。得到新的二元组。
然后问题就在于二元组合并。懒得写公式了:
最后面的只与$Q$有关。可以预处理。我们对于每个$pair$把$second$分解质因数这样就能在合法的复杂度内求出$varphi$和枚举约数。
然后就没了。但是因为没开$O2$所以$STL::map$超慢。手写哈希表是必要的(存$F$用)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 211111 4 #define mod 998244353 5 int w[S],al[S],n,ans,A[S],B[S],C[S],D[S],a[S],b[S],c[S],d[S],X,Y,T[S]; 6 vector<int>_dv[S],_t[S]; 7 struct hashmap{ 8 #define $ 10000007 9 int fir[$],l[$],to[$],v[$],ec; 10 int&operator[](int x){int r=x%$; 11 for(int i=fir[r];i;i=l[i])if(to[i]==x)return v[i]; 12 l[++ec]=fir[r];fir[r]=ec;to[ec]=x;return v[ec]; 13 } 14 }F; 15 int mo(int x){return x>=mod?x-mod:x;} 16 int gcd(int a,int b){return b?gcd(b,a%b):a;} 17 struct s{ 18 int a; vector<int>b,t; 19 void init(int x,int y,int z,int w){ 20 a=1ll*x*y*gcd(z,w)%mod; 21 for(int i=0;i<_dv[z].size();++i)T[_dv[z][i]]=max(T[_dv[z][i]],_t[z][i]); 22 for(int i=0;i<_dv[w].size();++i)T[_dv[w][i]]=max(T[_dv[w][i]],_t[w][i]); 23 for(int i=0;i<_dv[z].size();++i)b.push_back(_dv[z][i]), t.push_back(T[_dv[z][i]]),T[_dv[z][i]]=0; 24 for(int i=0;i<_dv[w].size();++i)if(T[_dv[w][i]])b.push_back(_dv[w][i]), t.push_back(T[_dv[w][i]]),T[_dv[w][i]]=0; 25 } 26 }x[S],y[S]; 27 int read(){ 28 register int p=0;register char ch=getchar(); 29 while(!isdigit(ch))ch=getchar(); 30 while(isdigit(ch))p=(p<<3)+(p<<1)+ch-48,ch=getchar(); 31 return p; 32 } 33 void init(int*M,int*m){ 34 for(int i=1;i<=n;++i)w[i]=read(),al[i]=0; 35 for(int i=1;i<=n;++i)if(!al[i]){ 36 int p=i,c=1;al[p]=1; 37 while(!al[w[p]])p=w[p],al[p]=1,c++; 38 M[c]++; 39 }for(int i=1;i<=n;++i)if(M[i])m[++m[0]]=i; 40 } 41 void ctb(int o,int n,int w){ 42 if(n==y[o].t.size()){F[w]=mo(F[w]+y[o].a);return;} 43 for(int j=0;j<=y[o].t[n];++j)ctb(o,n+1,w),w*=y[o].b[n]; 44 } 45 int ask(int o,int n,int w,int phi,int ans=0){ 46 if(n==x[o].t.size())return 1ll*F[w]*phi%mod; 47 for(int j=0;j<=x[o].t[n];++j)ans=mo(ans+ask(o,n+1,w,phi)),w*=x[o].b[n],phi=1ll*phi*(x[o].b[n]-(j?0:1)); 48 return ans; 49 } 50 int main(){//freopen("space20.in","r",stdin); 51 cin>>n;init(A,a);init(B,b);init(C,c);init(D,d); 52 for(int i=2;i<=n;++i)if(_dv[i].empty())for(int j=i;j<=n;j+=i){ 53 int x=j,c=0;_dv[j].push_back(i); 54 while(x%i==0)c++,x/=i; _t[j].push_back(c); 55 } 56 for(int i=1;i<=a[0];++i)for(int j=1;j<=b[0];++j)x[++X].init(A[a[i]],B[b[j]],a[i],b[j]); 57 for(int i=1;i<=c[0];++i)for(int j=1;j<=d[0];++j)y[++Y].init(C[c[i]],D[d[j]],c[i],d[j]); 58 for(int i=1;i<=Y;++i)ctb(i,0,1); 59 for(int i=1;i<=X;++i)ans=(ans+1ll*x[i].a*ask(i,0,1,1))%mod; 60 cout<<(ans+1ll*n*n%mod*n%mod*n)%mod<<endl; 61 }
T2:party
大意:树上有些点上有人,要求移动后形成一个联通块。(每点最多一个人)最小化总移动距离。$n le 200$
神仙神仙神仙题。
设$dp[i][j]$表示,以$i$为根的子树中,不考虑$i$节点上的人,剩下在子树内形成了一个大小为$j$的联通块的最小代价。
默认剩下的$cnt-j$个人都围在$i$点上,且不考虑从$i$子树外到达$i$所用的步数。
那么在我们枚举一个根节点之后进行$dp$。考虑加入一个子树时会发生什么:
1)最后这个子树里一个人也没有。$dp[i][j]+=dp[son][0]+cnt[son]$。就是所有堆在$son$的人都上涌到$i$。因为不考虑从上面来的代价,所以只有$cnt[son]$有代价。
2)枚举这个子树里最后有多少人。$dp[i][j]=minlimits_{k=1}^{j} (dp[i][j],dp[i][j-k]+dp[son][k]+ | k-sz[son] | )$
这里的绝对值非常妙。因为让外部走入和从内部走出的代价都是这个差值。
具体实现类似于一个背包。为了本层只更新本层,所以要倒着枚举$j$。
总的时间复杂度是$O(n^3)$的。
T3:wang
大意:要求设计值域定义域均为$Z$的函数$F$满足$F(2F(x)-x+1)=F(x)+C$。($C$为给定常数)。给定$n$对$(X,Y)$要求最小化$sumlimits_{i=1}^{n} | F(X_i) - Y_i |$
这个函数的奇怪性质肯定有好多要研究的地方。函数嵌套非常不爽,于是我们设$y=2F(x)-x+1$
现在代回去好看一些:$F(y)=x+C$。
两边同时$+C:F(y)+C=x+2C$
然后等式左边就变成了原始式子右边的形式,推回到左边来得到:$F(2F(y)-y+1)=x+2C$
把左边的$2F(y)$再代回$F(y)=F(x)+C$。剩余的$y$代回$y=2F(x)-x+1$
然后惊喜的发现式子就只剩下了$F(x+2C)=F(x)+2C$
这是个好性质。我们可以把括号内外的$2C$丢进来或撇出去。那么最简单的想法就是,在外部加上等量数后,内部可以对$2C$取模。
也就是说,只要确定了$F(x)$的值,那么$F(x+2C),F(x+4C)...$就都确定了。
所以说其实我们可以把$F(x)$表示为$t+nC$的形式。其中$0 le t < 2C$。至此还有两种表示方法,但是先往下看着。
$F(2F(x)-x+1)=F(x)+C$
可以代换了:$F(2t+2nC-x-1)=t+nC+C$
然后上面已经说明$2C$可以提出,那么左边的$2nC$就可以拿出来了:$F(2t-x-1)+2nC=t+nC+C$
也就是$F(2t-x+1)=t-nC+C$
我们发现这时候在函数自变量里的$x$由正变为了负,我们把正的一项加回来,就能得到$F(x)+F(2t-x+1)=2t+C$
换句话说,对于任意一对奇数偶数,若$a+b=2t+1,F(x)=t+nC$那么就有$F(a)+F(b)=2t+C$
所以说,在$F(x)=t+nC(0 le t <2C)$的两种表达方式中,其中一种没什么用,而$t,x$奇偶性不同的那一种它有所限制。(当然两种表达形式都是成立的
而我们又限定了$0 le t <2C$,也就是说,每个奇数一定对应某个特定偶数。某个偶数一定对应特定奇数。
一旦$F(x)=t+nC$确定,那么$F(2t+1-x)$也就同时确定了。这也可见,对应关系是双向的,且每个数的度数均为一。
于是我们就知道,$C$个奇数与$C$个偶数之间,存在完美匹配。这就是二分图匹配问题。
回归原问题,我们要最小化纵坐标的差绝对值。我们所需要决定的只是配对关系,配对关系确定$t$也就确定了,然后$n$只要取该配对关系下的最优值即可。
我们确定其中一个配对关系之后,那么这两个点的$F$值就同时确定了,模$2C$之后横坐标对应这两个点的代价也就确定了。
所以说每种配对的贡献是可以分开计算的。我们现在来考虑某个配对$a,b$的代价。这就是我们配对时这条边的边权。
沿用上面的定义,$a+b=2t+1$
那么对于所有模$2C$后是偶数$a$的点$(X_i,Y_i)$,它贡献的代价是$| lfloor frac{X_i}{2C} floor imes 2C + F(a) -Y_i|$
如果$F(a)=t+nC$那么就有$| lfloor frac{X_i}{2C} floor imes 2C + t+nC -Y_i|$
同时$F(b)$也就确定了,是$2t+C - F(a) = t -nC + C$
那么对于所有模$2C$后是偶数$a$的点$(X_i,Y_i)$,它贡献的代价是$| lfloor frac{X_i}{2C} floor imes 2C + F(b) -Y_i|$
即为$| lfloor frac{X_i}{2C} floor imes 2C + t-nC+C -Y_i|$
两种贡献中未知量只有$n$。我们把第二个式子的形式变一下:
绝对值内取相反数结果不变,那么就是$| - lfloor frac{X_i}{2C} floor imes 2C - t + nC - C +Y_i|$
这样,我们需要的就是一个合适的$n$值使两种贡献加起来尽量小。
考虑另一个经典的问题模型:已知若干$x_i$,求一个$x$,最小化$sumlimits |x_i -x|$。答案是$x$是$x_i$的中位数
在这里也只需要让$nC$尽量成为上述两种表达式对应的所有值的中位数即可。
然后就只需要一个$MCMF$来进行最大权匹配了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 66666 4 int n,C,CC,_x,xa,xb,xp,_y,ya,yb,yp,fir[123],l[S],to[S],v[S],ec=1,q[S],iq[123]; 5 long long w[S],d[S],ans,f[S]; 6 void link(int a,int b,int V,long long W){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;w[ec]=W;} 7 void con(int a,int b,long long W){link(a,b,1,W);link(b,a,0,-W);} 8 vector<int>X[123],Y[123]; 9 bool bfs(){ 10 memset(d,0x3f,sizeof d); memset(iq,0,sizeof iq); d[CC]=0; q[1]=CC; 11 for(int h=1,t=1;h<=t;iq[q[h++]]=0)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&d[to[i]]>d[q[h]]+w[i]){ 12 d[to[i]]=d[q[h]]+w[i]; if(!iq[to[i]])iq[q[++t]=to[i]]=1; 13 }return d[CC+1]<1e17; 14 } 15 int dfs(int p,int f){int r=f; 16 if(p==CC+1)return f; iq[p]=1; 17 for(int i=fir[p];i&&r;i=l[i])if(v[i]&&d[to[i]]==d[p]+w[i]&&!iq[to[i]]){ 18 int x=dfs(to[i],1); 19 if(!x)d[to[i]]=-1; 20 else v[i]--,v[i^1]++,ans+=w[i],r--; 21 }return f-r; 22 } 23 long long cal(int a,int b){ 24 int c=0,t=a+b>>1,nC1,nC2;long long f1=0,f2=0; 25 for(int i=0;i<X[a].size();++i)f[++c]=-(X[a][i]/CC*CC+t-Y[a][i]); 26 for(int i=0;i<X[b].size();++i)f[++c]=X[b][i]/CC*CC+t-Y[b][i]+C; 27 sort(f+1,f+1+c); 28 nC1=floor(f[c+1>>1]*1./C)*C;nC2=ceil(f[c+1>>1]*1./C)*C; 29 for(int i=1;i<=c;++i)f1+=abs(f[i]-nC1),f2+=abs(f[i]-nC2); 30 return min(f1,f2); 31 } 32 int main(){ 33 cin>>C>>n>>_x>>xa>>xb>>xp>>_y>>ya>>yb>>yp; CC=C+C; 34 for(int i=0;i<n;++i)X[_x%CC].push_back(_x),Y[_x%CC].push_back(_y),_x=(1ll*_x*xa+xb)%xp,_y=(1ll*_y*ya+yb)%yp; 35 for(int i=0;i<CC;i+=2)for(int j=1;j<CC;j+=2)con(i,j,cal(i,j)); 36 for(int i=0;i<CC;++i)if(i&1)con(i,CC+1,0);else con(CC,i,0); 37 while(bfs())dfs(CC,C); cout<<ans; 38 }