每次做arc都感觉虽然很难但很有意思
A.Odd vs Even
第一个想法是包含2的次数有关。很容易想到,若这个数是奇数,那它一定没有偶数因子。再通过打表后我们可以发现:若2的次数只有1次,那么,奇数因子数=偶数因子数。若2的次数更大,那偶数因子数>奇数因子数。
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//clock_t c1 = clock();
//===========================================================
read(t);
while(t--){
read(n);
if(n&1){
puts("Odd");
}
else{
if(n==2)puts("Same");
else{
int cnt=0;
while(n%2==0)cnt++,n/=2;
if(cnt>1)puts("Even");
else puts("Same");
}
}
}
//===========================================================
//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
B.Products of Min-Max
算贡献的题目。
(1)、首先需要对只有一个数的子序列处理。先求出每个数的平方的和作为答案的一部分。
(2)、接下来考虑子序列长度大于1的情况:考虑对于每一对乘积a*b,它贡献的次数就是以a为最小值,b为最大值的子序列的个数。那么,就是考虑填入大小在a~b之间的数,那么,每个数都可以选择出现和不出现。
因此,假设a和b在排序后的数组中的下标分别为i和j,那么,以a为最大,b为最小的序列数目就有
2
i
−
j
−
1
2^{i-j-1}
2i−j−1。
因此,对于情况2,我们可以列出式子(a数组已经排好序):
∑
i
=
1
n
∑
j
=
i
+
1
n
a
i
∗
a
j
∗
2
i
−
j
−
1
=
1
2
∑
i
=
1
n
a
i
2
i
∑
i
=
j
+
1
n
a
j
2
−
j
\sum_{i=1}^n\sum_{j=i+1}^na_i*a_j*2^{i-j-1}={1\over 2}\sum_{i=1}^na_i2^i\sum_{i=j+1}^na_j2^{-j}
i=1∑nj=i+1∑nai∗aj∗2i−j−1=21i=1∑nai2ii=j+1∑naj2−j
然后后缀和优化下求值就好了。
const int maxn=2e5+10;
#define int ll
int n,a[maxn];
ll val1[maxn],val2[maxn];
ll sum1[maxn],sum2[maxn];
ll w1[maxn],w2[maxn];
ll inv2=ksm(2,mod-2);
ll solve(){
sort(a+1,a+1+n);
ll res=0;
for(int i=1;i<=n;++i)res=(res+a[i]*a[i]%mod)%mod;
w1[0]=1;
for(int i=1;i<=n;++i){
w1[i]=w1[i-1]*inv2%mod;
//cerr<<w1[i]<<" ";
//cerr<<w1[i]*ksm(2,i)%mod<<endl;
}
w2[0]=1;
for(int i=1;i<=n;++i){
w2[i]=w2[i-1]*2%mod;
//cerr<<w2[i]<<" ";
}
for(int i=1;i<=n;++i){
val1[i]=a[i]*w1[i]%mod;
}
for(int i=1;i<=n;++i){
val2[i]=a[i]*w2[i]%mod;
}
ll p2=0;
for(int i=1;i<=n;++i)sum1[i]=sum1[i-1]+val1[i],sum1[i]%=mod;
for(int i=n;i>=1;--i)sum2[i]=sum2[i+1]+val2[i],sum2[i]%=mod;
for(int i=1;i<n;++i){
p2=(p2+val1[i]*sum2[i+1]%mod)%mod;
}
res=(p2*inv2+res)%mod;
return res;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
//clock_t c1 = clock();
//===========================================================
read(n);
rep(i,1,n)read(a[i]);
cout<<solve()<<endl;
//===========================================================
//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
return 0;
}
C.Multiple Sequences
这道题没有写出来,看了别人的证明之后感觉真的妙啊Orz
cf讨论区
首先,这个数列需要满足
a
i
a_i
ai为
a
i
−
1
a_{i-1}
ai−1的倍数,那么,我们其实可以关注到最后一个数a[n]应该是某种意义上的“集大成者”(?),也就是说,它肯定是数列中其他元素的倍数。
接下来的分析来自讨论区:
对于某个确定的
a
n
a_n
an,因为前面的数一定是
a
n
a_n
an的因数,所以,有以下结论:
(1).若
a
n
=
p
1
Q
1
p
2
Q
2
…
…
p
k
Q
k
a_n=p_1^{Q_1}p_2^{Q_2}……p_k^{Q_k}
an=p1Q1p2Q2……pkQk,对于任意的
a
i
=
p
1
q
1
p
2
q
2
…
…
p
k
q
k
a_i=p_1^{q_1}p_2^{q_2}……p_k^{q_k}
ai=p1q1p2q2……pkqk,有
Q
1
>
=
q
1
,
Q
2
>
=
q
2
…
…
Q
k
>
=
q
k
Q_1>=q_1,Q_2>=q_2……Q_k>=q_k
Q1>=q1,Q2>=q2……Qk>=qk
(2).若
a
n
=
p
1
Q
1
p
2
Q
2
…
…
p
k
Q
k
a_n=p_1^{Q_1}p_2^{Q_2}……p_k^{Q_k}
an=p1Q1p2Q2……pkQk,对于其中的某一个质因数p,我们设
y
i
=
q
i
−
q
i
−
1
y_i=q_i-q_{i-1}
yi=qi−qi−1(其中
q
i
q_i
qi为质数p在i中的次数,
q
i
−
1
q_{i-1}
qi−1同理),则有
∑
i
=
1
n
y
i
=
Q
\sum_{i=1}^{n}y_i=Q
i=1∑nyi=Q
因此,这个问题就可以看成
∑
i
=
1
n
y
i
=
Q
\sum_{i=1}^{n}y_i=Q
∑i=1nyi=Q这个关于
y
i
y_i
yi的方程有多少个非负整数解,显然,很经典的问题,就是
C
n
+
Q
−
1
n
−
1
C_{n+Q-1}^{n-1}
Cn+Q−1n−1(隔板法/生成函数)。
剩下的细节看代码应该就能理解了。
const int maxn=4e5+10;
const int mod=998244353;
#define int ll
bool vis[maxn];
int pri[maxn],tot;
ll f[maxn],finv[maxn];
ll ksm(ll a,ll n){
ll res=1;
while(n){
if(n&1)res=res*a%mod;
a=a*a%mod;
n>>=1;
}
return res;
}
void init(){
f[0]=1;
for(int i=1;i<maxn;++i)f[i]=f[i-1]*i%mod;
finv[maxn-1]=ksm(f[maxn-1],mod-2);
for(int i=maxn-2;i>=0;--i){
finv[i]=finv[i+1]*(i+1)%mod;
}
for(int i=2;i<maxn;++i){
if(!vis[i])pri[++tot]=i;
for(int j=1;j<=tot&&i*pri[j]<maxn;++j){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
}
}
}
ll C(ll n,ll m){
return f[n]*finv[n-m]%mod*finv[m]%mod;
}
ll n,m;
signed main(){
//freopen("in.txt","r",stdin);
init();
ll ans=0;
read(n),read(m);
for(int i=1;i<=m;++i){
int now=i;
ll res=1;
for(int j=1;j<=tot&&pri[j]*pri[j]<=now;++j){
if(now%pri[j]==0){
int cnt=0;
while(now%pri[j]==0){
++cnt;
now/=pri[j];
}
res=res*C(n+cnt-1,n-1)%mod;
res%=mod;
}
}
if(now>1)res=res*C(n,n-1)%mod,res%=mod;
ans=(ans+res)%mod;
}
cout<<ans<<endl;
return 0;
}