11月30日考试 题解
T1
原题:CF1416A
显然数$c$为$k$连数当$k$大于等于其所有出现位置中相邻位置距离最大值。然后随便做。时间复杂度$O(n\log n)$,可以优化到$O(n)$。
T2
原题:P5857
计数蒟蒻实锤QAQ。
可以发现,当一行/列的状态被改变时,它一定被异或了奇数次。若有$i$行$j$列被异或了奇数次,那么对答案的贡献是$\binom{n}{i}\times \binom{m}{j}$,其中$i,j$与$k$奇偶性相同(奇×奇=奇,偶×奇=偶)。然后考虑去重。当两种方案所达到最后矩阵的状态相同时,这两种方案是重复的。不难发现只有当$n,m$均为偶数时,才有可能发生这种情况(方案可以对称过去)。对于一组合法的$i,j$,当$n-i,m-j$与$k$奇偶性相同时,这两种方案是重复的。可以分开统计总方案数和重复的方案数,然后减一下即可。
代码:
#include<cstdio> #include<iostream> #define int long long using namespace std; const int N=200000; const int mod=998244353; int fac[N+5],inv[N+5],n,m,k,T; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } inline int qpow(int x,int y) { int res=1; while(y) { if (y&1) res=(res*x)%mod; x=(x*x)%mod; y>>=1; } return res; } inline int C(int x,int y){ return fac[x]*inv[y]%mod*inv[x-y]%mod; } signed main() { fac[0]=inv[0]=1; for (int i=1;i<=N;i++) fac[i]=(fac[i-1]*i)%mod; inv[N]=qpow(fac[N],mod-2); for (int i=N-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%mod; T=read(); while(T--) { n=read();m=read();k=read(); int ax=0,ay=0,bx=0,by=0,nn=min(n,k),mm=min(m,k); for (int i=nn%2;i<=nn;i+=2) ax=(ax+C(n,i))%mod; for (int i=mm%2;i<=mm;i+=2) ay=(ay+C(m,i))%mod; if (n%2==0&&m%2==0) { int l=max(n-k,0ll),r=min(n,k); for (int i=l;i<=r;i+=2) bx=(bx+C(n,i))%mod; l=max(m-k,0ll),r=min(m,k); for (int i=l;i<=r;i+=2) by=(by+C(m,i))%mod; } printf("%lld\n",(ax*ay%mod-bx*by%mod*inv[2]%mod+mod)%mod); } return 0; }
T3
题目大意:给定一棵树,求$\sum\limits_{i=1}^n \sum\limits_{j=i+1}^n (a_i\ xor\ a_j)\times dist(i,j)$。其中每条边边权为$1$。
首先可以对每一位分别统计贡献。发现边权为$1$,不妨考虑对每条边统计贡献,看它被经过多少次。两个数异或对答案有贡献当且仅当这两位不相同。所以统计一下子树内$0$的个数和$1$的个数然后乘起来即可。最后相加即为答案。
T4
题目大意:给定$n$个体积小于等于$k$的物品和一个体积为$m$的背包。当背包容量分别为$1$到$m$时求能装的最大价值。$n\leq 500000,k\leq 5$。
正解不太懂,只会一个正确性不知道怎么证明的乱搞做法……暂且说一下吧。
首先按照性价比从大到小排序,然后维护一个后缀的背包。设$g[i][j]$表示考虑到$i$时剩余量为$j$的最大价值,倒着枚举$i$。这个剩余量比较玄学,设成85左右即可。这样做的意义在于:我们的策略肯定是选一部分前缀,然后在后面选一部分。然后维护一个$ans$统计答案即可。
AlanSP有一个神仙决策单调性做法orz,可以去看看他的博客。
代码:
#include<cstdio> #include<iostream> #include<algorithm> #define all 100 #define int long long using namespace std; const int N=500005; int n,m,k,g[N][105],ans[N],now,val; struct node{ int w,v; }p[N]; inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} return x*f; } bool cmp(node x,node y){ return x.v*y.w>y.v*x.w; } signed main() { n=read();m=read();k=read(); for (int i=1;i<=n;i++) p[i].w=read(),p[i].v=read(); sort(p+1,p+n+1,cmp); for (int i=n;i>=1;i--) { for (int j=all;j>=p[i].w;j--) g[i][j]=g[i+1][j-p[i].w]+p[i].v; for (int j=0;j<=all;j++) g[i][j]=max(g[i][j],g[i+1][j]); } for (int i=1;i<=n;i++) { for (int j=0;j<=all;j++) ans[now+j]=max(ans[now+j],val+g[i][j]); now+=p[i].w;val+=p[i].v; } for (int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; }