zoukankan      html  css  js  c++  java
  • [考试反思]数学专题测试3:发现

    唔。。。咕了好久啊。。。但是对我而言联赛后能得一次rk1简直难于上青天,所以还是要写博客纪念一下的。

    其实这场考试也没什么好说的,又不是凭什么真正的知识储备取得的成绩。。。

    只不过是大神们不稀罕用打表之类无聊的手段,刚好被我抓住了一次机会而已。

    赶巧T1和T3的区分度都不大,况且我T3还炸了,只不过T2侥幸打表找到了规律恰好T2没有规律就根本不可做,所以拉开了分差。。。

    这场考试简直就像是上天安排的对菜鸡的一次安慰一样。

    就算你啥都不会,只要运气够好就可以rk1

    其实也是挺巧,因为之前刚颓过《color有色图》的题解知道了分配去重的技巧所以拿到了第二档部分分。

    因为多数人都认为现在做那种大神题是在浪费题,所以只有少数人颓了题解2333于是我又赚了

    T2打了一个小时表。。。我估计其他人应该是不会把如此大量的时间花在这上面吧。。。但没办法啊我啥都不会除了打表还能怎么办啊?

    于是就把大神们用来思考的时间拿来打表。。。在大量的猜测之下就随便写了一个,抱着稳住n=7的10分其余随意的心态就写了

    我感觉最近一段时间的rp应该都差不多透支完了

    T3做的不好。首先读题不认真,题目给的是点值没细看当成系数做了,调了一个小时样例。。。

    不会拉格朗日插值于是少了一档暴力分,而且式子非常冗余可以化简导致消元之外的复杂度比别人多个n。

    其实高斯消元就足以拿到30+5分,但是因为式子太麻烦常数过大被卡成15+5分。

    如果把这些侥幸的因素去掉,就是rk9了啊。。。

    但是不得不说:

    打表是真的爽!

    乱搞的确是有用的技巧!

    (虽说我到目前为止打表的成功率也就30%左右,但是那种题目只输入1个参数的题还是可以试一试的)

    T1:young

    题目大意:n点图,点权$[0,2^m)$内随机,边权为两点异或。求所有情况下最小生成树权和。$mod 258280327=2 imes 3^{17}+1$

    对于$30\%$的数据$n imes m le 16$。对于$50\%$的数据$m le 4$。对于$100\%$的数据$n le 50,m le 8$。

    这题部分分可以讲一下。

    $30\%$搜索。

    $50\%$,点权相同的点可以合并,点编号与答案无关,于是将点按权去重排序,后者严格大于前者再搜索,整数加法分配,状态数不多。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mod 258280327
     4 int C[55][55],f[55],n,m,ans,v[55],N=1,fa[55];
     5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
     6 struct Ed{int a,b,v;friend bool operator<(Ed x,Ed y){return x.v<y.v;}}E[1234];
     7 int find(int p){return fa[p]==p?p:fa[p]=find(fa[p]);}
     8 void sch(int al){
     9     if(al==N+1){
    10         int ec=0,c=0; for(int i=1;i<=N;++i)fa[i]=i;
    11         for(int i=1;i<=N;++i)for(int j=i+1;j<=N;++j)E[++ec]=(Ed){i,j,v[i]^v[j]};
    12         sort(E+1,E+1+ec);
    13         for(int i=1,A=0;A<n&&i<=ec;++i)if(find(E[i].a)!=find(E[i].b))fa[fa[E[i].a]]=fa[E[i].b],c+=E[i].v,A++;
    14         ans=(ans+1ll*f[N]*c)%mod;
    15         return;
    16     }for(int j=v[al-1]+1;j<1<<m;++j)v[al]=j,sch(al+1);
    17 }
    18 int main(){
    19     cin>>n>>m;v[0]=-1;
    20     for(int i=0;i<=50;++i)C[i][0]=f[i]=1;
    21     for(int i=1;i<=50;++i)for(int j=1;j<=n;++j)f[i]=f[i]*1ll*i%mod;
    22     for(int i=1;i<=50;++i)for(int j=1;j<=i;++j)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    23     for(int i=1;i<=50;++i)for(int j=1;j<i;++j)f[i]=(f[i]-1ll*f[j]*C[i][j]%mod+mod)%mod;
    24     for(;N<=n;++N)sch(1);
    25     cout<<1ll*ans*qp(qp(2,n*m),mod-2)%mod<<endl;
    26 }
    View Code

    $100\%$的话就是大神$dp$了。设$f(n,m)$表示$n$点$2^m$权图的最小生成树权和。

    $g(s,t,m)$表示所有情况下大小为$s,t$的两个点集,权范围为$2^m$时所有情况中使两个点集联通的最小代价之和。

    $p(s,t,m,k)$表示两个点集之间连边边权大于等于$k$的方案数。注意是方案数而不是权。

    存在转移$g(s,t,m)=sumlimits_{i=1}^{2^m-1} p(s,t,m,i)$。这比较显然。

    考虑$f$的转移。对于当前的$n$的点的第$m$位,我们将它按照这一位上是$0$还是$1$分成两组。

    设这一位是$0$的点集为$s$。其余为$t$。我们枚举$s$。

    如果$s=0$或$t=0$那么无论如何连边都不会产生这一位为$1$的代价。否则想让它们联通就一定有$2^{m-1}$的代价。不论更低位是几。

    所以只要$s,t$同时存在那么就会产生$2^{m-1} imes (2^{m-1})^{n}=2^{(m-1)(n+1)}$。乘号后面那个的含义就是所有点随便选。

    这样的话这一位的贡献我们考虑完了,我们分别去考虑$s$内部,$t$内部与$s,t$之间的连边。

    前两者这一位没有贡献就是$f(s,m-1) imes 2^{(m-1)(n-i)}+f(t,m-1) imes 2^{(m-1)s}$。后者去掉当前位的贡献就是$g(s,t,m-1)$。

    前面乘2的幂是表示,因为$s,t$两个点集是独立计算的,而你要计算所有情况,所以对于每种可能的$t$集都会让所有的$s$集贡献答案。

    所以总的转移式就是:

    $f(n,m)=sumlimits_{s=0}^{n} C_n^s(2^{(m-1)(n-i)}f(s,m-1)+ 2^{(m-1)s}f(t,m-1) + g(s,t,m-1) + [s eq 0&t eq 0] imes 2^{(m-1)(n+1)} )$

    接下来就只剩下了$p$的转移。大致意思差不多,但是是方案数。

    分别讨论$s$与$t$集合中这一位是$0$和$1$的点数,再依据$k$这一位是$0/1$分类讨论。

    因为你会连最小的边,所以当$(s0,t0)$或$(s1,t1)$同时存在时你这一位一定是$0$。

    所以如果$k$这一位上是$1$那么一定代表只存在$(s0,t1)$或$(s1,t0)$。递归处理,答案就是$2 imes p(s,t,m-1,k xor (1<<m-1))$

    如果$k$这一位上是$0$,那么就直接枚举$s0,t0$的大小,两边互不影响方案数相乘,再乘上选点的组合数。

    转移到此为止,但是还要考虑递归边界的问题。

    对于$f$。当点数或权为$0$时答案当然是$0$。$g$也是同理。

    但是$p$不是。$p$是方案数。如果$m=0$那么一定代表这$k=0$,因为高位的$1$都被消去了,所以贡献$1$的方案。

    而考虑如果有一个点集为$0$了。那么无论如何连边都不能使之联通,代价为$infty geq k$。所以另一个点集可以任选。

    递归边界卡紧。再加一个剪枝就是,因为$s,t$点集的顺序是无关的,保证$sle t$。再加一发记忆化,搜就行了。

    理论复杂度$O(n^4m2^m)$。然而实际运行效率很优秀。不行就把表打出来也可以。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mod 258280327
     4 unordered_map<int,int>f[55],g[55][55],p[55][55][9];
     5 int C[55][55],n,m,ans,N=1,pw[405];
     6 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
     7 int mo(int x){return x>=mod?x-mod:x;}
     8 int P(int S,int T,int m,int k){
     9     if(S>T)S^=T^=S^=T; if(!m)return !k; if(!S)return pw[T*m];
    10     if(p[S][T][m].find(k)!=p[S][T][m].end())return p[S][T][m][k];
    11     int ans=0;
    12     if(k&1<<m-1)return p[S][T][m][k]=mo(P(S,T,m-1,k^1<<m-1)<<1);
    13     for(int s=0;s<=S;++s)for(int t=0;t<=T;++t)if((s+T-t)*(t+S-s))ans=(ans+1ll*P(s,t,m-1,k)*P(S-s,T-t,m-1,k)%mod*C[S][s]%mod*C[T][t])%mod;
    14     return p[S][T][m][k]=mo(ans+pw[(S+T)*(m-1)+1]);
    15 }
    16 int G(int S,int T,int m){
    17     if(S>T)S^=T^=S^=T; if(!m||!S)return 0;
    18     if(g[S][T].find(m)!=g[S][T].end())return g[S][T][m];
    19     int ans=0;
    20     for(int k=1;k<1<<m;++k)ans=mo(ans+P(S,T,m,k));
    21     return g[S][T][m]=ans;
    22 }
    23 int F(int n,int m){
    24     if(!m||n<=1)return 0;
    25     if(f[n].find(m)!=f[n].end())return f[n][m];
    26     int ans=0;
    27     for(int i=0;i<=n;++i)ans=(ans+(1ll*pw[(n-i)*(m-1)]*F(i,m-1)+1ll*pw[i*(m-1)]*F(n-i,m-1)+G(i,n-i,m-1)+(i&&i!=n?pw[(n+1)*(m-1)]:0))%mod*C[n][i])%mod;
    28     return f[n][m]=ans;
    29 }
    30 int main(){
    31     for(int i=0;i<=50;++i)C[i][0]=1;pw[0]=1;
    32     for(int i=1;i<=50;++i)for(int j=1;j<=i;++j)C[i][j]=mo(C[i-1][j-1]+C[i-1][j]);
    33     for(int i=1;i<=400;++i)pw[i]=mo(pw[i-1]<<1);
    34     cin>>n>>m;cout<<1ll*qp(pw[n*m],mod-2)*F(n,m)%mod<<endl;
    35 }
    View Code

    T2:simple

    题目大意:对于所有可含前导0的n位数$X$若其满足任意$1 le k < n,X imes 10^k   mod 10^n >X$,则产生$n^2$。贡献。求所有$kle n$位数的贡献。

    对于$10\%$的数据$n=7$。对于$100\%$的数据$n=10^{10},mod=258280327=2 imes 3^{17}+1$。

    对于这种只读入一个参数的题目可以考虑打表。

    正解是考虑那个式子的含义,其实是十进制下的左移,对于有循环节的数显然不成立,否则对于$n$位数它的最大循环位移合法其余均不合法。

    所以答案是$sumlimits_{i=1}^{n} i^2 sumlimits_{d|i} mu(frac{i}{d}) frac{10^i}{d}$

    化简,再套个等差成等比,发现要求的就是$i imes mu(i)$的前缀和。卷个$id$就可以杜教筛。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 20000005
     4 #define mod 258280327 
     5 #define ll long long
     6 const int I9=229582513,I81=1ll*I9*I9%mod;
     7 unordered_map<int,int>Mu;
     8 int p[S],M,pc,mu[S];char np[S];ll n;
     9 int MU(ll x){int a=1;
    10     if(x<M)return mu[x]; if(Mu.find(x)!=Mu.end())return Mu[x];
    11     for(ll i=2,N,l;N=x/i,i<=x;i=l+1)l=x/N,a=(a-(l-i+1ll)%mod*(i+l)%mod*129140164%mod*MU(N)%mod+mod)%mod;
    12     return Mu[x]=a;
    13 }
    14 int qp(ll b,ll t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
    15 ll cal(ll n){ll P=qp(10,n+1);return ((n*P-10)%mod*I9%mod-(P-100)*I81%mod+mod)%mod;}
    16 int main(){//freopen("1.in","r",stdin);
    17     cin>>n;M=pow(n,0.72);mu[1]=1;
    18     for(int i=2;i<M;++i){
    19         if(!np[i])mu[p[++pc]=i]=-i;
    20         for(int j=1,x;j<=pc&&(x=p[j]*i)<M;++j)
    21             if(i%p[j])np[x]=1,mu[x]=-mu[i]*p[j];
    22             else {np[x]=1;break;}
    23     }int a=0;
    24     for(int i=2;i<M;++i)mu[i]=(mu[i-1]+mu[i]+0ll+mod)%mod;
    25     for(ll i=1,N,l,cl=0,cn;N=n/i,i<=n;i=l+1)l=n/N,cn=cal(l),a=(a+1ll*(cn-cl+mod)%mod*MU(N))%mod,cl=cn;
    26     cout<<a<<endl;
    27 }
    View Code

    T3:小H爱染色(Loj2504)

    题目大意:编号$[0,n)$的球连续两次可重地从中挑取$m$个染色。求所有方案下$F(A)$的期望。$A$表示被染色球中编号最小的。

    给出对于$0le i le m$的$F(i)$值。你可以认为$F$是个不高于$m$次的多项式。

    对于$100\%$的数据,$n le mod=998244353,m le 10^6$

    据说严重卡常。看了式子挺暴力的。上网直接搜题解。用空回来填坑。

    大体分两种做法.

    第一种可以看这个博客,我没有写。

    第二种做法比较神奇,看着题解弄了半天,拿出来说一说。

    对于$F(x)=x$。我们换一个角度来思考问题,转化一下问题含义:设$A$表示某一种选法得到的最小黑球。

    问题可以转化为:求期望有多少个白球其左侧没有黑球。也即期望有多少球编号小于$A$

    我们分开讨论每个球的贡献。枚举最终黑色球的数量$k(m le k le 2m)$。

    那么算上正在做贡献的白球,一共有$k+1$个。选法是$C_n^{k+1}$种。这样选出来,最靠左的就是白的,剩下的就是黑的,与每种方案对应上了。

    但是还没有完。关于你是怎么选出这$k$个的,分两轮选。

    第一轮选的肯定在这$k$个里面乱选的,方案数是$C_k^m$。

    第二轮一定会选没被选过的$k-m$个,剩下$m-(m-k)$个在选过的里乱选乱选,方案数是$C_{m}^{2m-k}$

    所以选出若干球的方案数$H_k=C_k^m imes C_{m}^{2m-k}$

    这个部分分的答案就是$sumlimits_{k=m}^{2m} H_k imes C_n^{k+1}$

    对于$F(x)=x^c$。还是转化题意,这次是:可重复的选$c$次球编号都小于$A$的方案数的期望。

    可重复不是很好处理,我们设$q$表示最后选择$c$次后被选过的球一共多少种。设方案数为$G_q$(就是第二类斯特林数乘阶乘)

    根据含义列式$q^c=sumlimits_{i=0}^{q} C_q^i G_i$。二项式反演一波得到$G_q=sumlimits_{i=0}^{q} (-1)^{q-i} C_q^i i^c$

    设$T_i$表示你选择的球和你染黑的球的总数为$i$的情况下的贡献。$T_i=sumlimits_{j=0}^{i} G_j H_{i-j}$

    $G,T$都是经典的卷积形式,直接$NTT$就可以了。

    对于所有数据。其实就是上面这个的复合,只要把$G$公式中$i^c$替换成$F(i)$就好了。

    所以就可以不用插值直接做了。时间复杂度$O(mlogm)$。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 3000003
     4 #define mod 998244353
     5 int n,m,fac[S],invv[S],inv[S],Cn[S],rev[S],N,f[S],a[S],G[S],H[S],T[S],ans;
     6 int C(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;}
     7 int qp(int b,int t,int a=1){for(;t;t>>=1,b=1ll*b*b%mod)if(t&1)a=1ll*a*b%mod;return a;}
     8 void NTT(int*a,int opt=1){
     9     for(int i=0;i<N;++i)if(rev[i]>i)swap(a[i],a[rev[i]]);
    10     for(int i=1;i<N;i<<=1)for(int j=0,b=qp(3,(mod-1)/2/i*opt+mod-1);j<N;j+=i<<1)
    11         for(int k=j,w=1,x,y;k<j+i;++k,w=1ll*w*b%mod)x=a[k],y=1ll*a[i+k]*w%mod,a[k]=(x+y)%mod,a[i+k]=(mod+x-y)%mod;
    12     if(opt==-1)for(int iv=qp(N,mod-2),i=0;i<N;++i)a[i]=1ll*a[i]*iv%mod;
    13 }
    14 int main(){
    15     fac[0]=invv[1]=inv[0]=fac[1]=inv[1]=Cn[0]=N=1;
    16     for(int i=2;i<S;++i)fac[i]=1ll*fac[i-1]*i%mod,invv[i]=(mod-mod/i+0ll)*invv[mod%i]%mod,inv[i]=1ll*inv[i-1]*invv[i]%mod;
    17     scanf("%d%d",&n,&m);
    18     for(int i=1;i<S;++i)Cn[i]=Cn[i-1]*(n-i+1ll)%mod*invv[i]%mod;
    19     for(int i=0;i<=m;++i)scanf("%d",&f[i]),f[i]=1ll*f[i]*inv[i]%mod,a[i]=i&1?mod-inv[i]:inv[i],H[i]=1ll*C(i+m,i)*C(m,i)%mod;
    20     while(N<=m<<1)N<<=1; for(int i=0;i<N;++i)rev[i]=rev[i>>1]>>1|(i&1?N>>1:0);
    21     NTT(f);NTT(a);
    22     for(int i=0;i<N;++i)G[i]=1ll*a[i]*f[i]%mod;
    23     NTT(G,-1);
    24     for(int i=0;i<=m;++i)G[i]=1ll*G[i]*fac[i]%mod;
    25     for(int i=m+1;i<N;++i)G[i]=0;
    26     NTT(G);NTT(H);
    27     for(int i=0;i<N;++i)T[i]=1ll*G[i]*H[i]%mod;
    28     NTT(T,-1);
    29     for(int i=0;i<=m<<1;++i)ans=(ans+1ll*Cn[i+m]*T[i])%mod; cout<<ans<<endl;
    30 }
    View Code
  • 相关阅读:
    shell脚本大小写转换
    python写xml及几个问题
    Java集合系列导读
    Java集合系列之Collection接口
    并发编程之锁机制
    Java中的堆内存和栈内存
    Java与ElasticSearch的交互操作
    ElasticSearch基础概念
    Java的对象和类
    Spring Validator参数校验
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12169550.html
Copyright © 2011-2022 走看看