AtCoder Regular Contest 116 总结

A

判断奇偶因子谁多谁少

容易发现如果质因数分解,有 n 个 2 和 m 个非 2 质因子

则奇数因子有 2m 个 ,偶数因子有 2n+m1 个(没有 2 时没有)

可知当 n=0 时奇数多, n=1 时一样, n=2 时偶数多

复制代码
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int t;
ll n;

int main() {
    for (scanf("%d",&t);t;t--) {
        scanf("%lld",&n);
        if (n%2!=0) {printf("Odd\n");continue;}
        n/=2;
        if (n%2!=0) {printf("Same\n");continue;}
        else printf("Even\n");
    }
}
View Code
复制代码

B

求对于一个序列 A ,它的子序列 B 的 Bmax(B)min(B)

将 A 排序,枚举左右端点为 l,r ,则当前答案为 a[l]a[r]2rl1(r>l) 再加上 a[l]a[r](r=l)

考虑用后缀和维护 a[r]2r1 则枚举左端点 l 时答案为 a[l]s[r]2l(r>l) 再加上 a[l]a[r](r=l)

时间复杂度 O(n)

复制代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll P=998244353;
const int N=2e5+10;
int n;
ll a[N],_2[N],suf[N],ans;

ll Pow(ll x,ll y) {ll ans=1;for (;y;y>>=1,x=x*x%P) if (y&1) ans=ans*x%P;return ans;}

int main() {
    scanf("%d",&n);
    _2[0]=1;for (int i=1;i<=n;i++) scanf("%lld",&a[i]),_2[i]=(_2[i-1]<<1)%P;
    sort(a+1,a+n+1);
    for (int i=n;i;i--)    suf[i]=(suf[i+1]+a[i]*_2[i-1]%P)%P;
    for (int i=1;i<=n;i++)
        (ans+=a[i]*suf[i+1]%P*Pow(_2[i],P-2)%P+a[i]*a[i]%P)%=P;
    printf("%lld\n",ans);
}
View Code
复制代码

C

在一个序列中不同的数至多有 log2m

则设 f[i][j] 表示第 i 个不同的数是 j , 从上一个 j 的因子里转移过来,复杂度是调和级数 O(nlnn)

最后枚举有 i 个不同的数,在 n-1 个空隙里插 i-1 个板即可

复制代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const ll P=998244353;
const int N=2e5+10;
int n,m,lg;
ll fact[N],inv[N],f[21][N],ans;

ll Pow(ll x,ll y) {ll ans=1;for (;y;y>>=1,x=x*x%P) if (y&1) ans=ans*x%P;return ans;}

ll C(int n,int m) {return fact[n]*inv[n-m]%P*inv[m]%P;}

int main() {
    scanf("%d%d",&n,&m);lg=log2(m);
    fact[0]=1;for (int i=1;i<N;i++) fact[i]=fact[i-1]*i%P;
    inv[N-1]=Pow(fact[N-1],P-2);for (int i=N-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%P;
    for (int i=1;i<=m;i++) f[0][i]=1;
    for (int i=1;i<=lg;i++)
        for (int j=1;j<=m;j++)
            for (int k=2;k*j<=m;k++) (f[i][j*k]+=f[i-1][j])%=P;
    for (int i=0;i<=min(lg,n-1);i++)
        for (int j=1;j<=m;j++) (ans+=f[i][j]*C(n-1,i))%=P;
    printf("%lld\n",ans);
}
View Code
复制代码

D

范围很小,做法很暴力

从低位到高位,设 f[i][j] 表示做到第 i 位,前面 i-1 位满足相消为 0 的方案数

O(mlogm)

复制代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const ll P=998244353;
const int N=5e3+10;
int n,m,lg;
ll fact[N],inv[N],f[15][N];

ll Pow(ll x,ll y) {ll ans=1;for (;y;y>>=1,x=x*x%P) if (y&1) ans=ans*x%P;return ans;}

ll C(int n,int m) {return fact[n]*inv[n-m]%P*inv[m]%P;}

int main() {
    scanf("%d%d",&n,&m);lg=log2(m);
    if (m&1) return printf("0"),0;
    fact[0]=1;for (int i=1;i<=n;i++) fact[i]=fact[i-1]*i%P;
    inv[n]=Pow(fact[n],P-2);for (int i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%P;
    f[0][0]=1;
    for (int i=0,k=1;i<=lg;i++,k<<=1)
        for (int j=0;j<=m;j++) {
            for (int l=2;j+k*l<=m&&l<=n;l+=2) (f[i+1][j+k*l]+=f[i][j]*C(n,l)%P)%=P;
            (f[i+1][j]+=f[i][j])%=P;
        }
    printf("%lld\n",f[lg+1][m]);
}
View Code
复制代码
posted @   Vagari  阅读(71)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示