AtCoder Grand Contest 023

链接

D. Go Home

考虑两端的最后一组到的人,如果左边的人数大于等于右边,那么右边的人只能希望左边的人快点到,所以他们会和左边的人投一样的票。然后就可以把这组人加到左边去,这样就变成了一个子问题。

最后全部在公司一侧了就直接开过去即可。复杂度 O(n)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100010
#define ll long long
using namespace std;
int x[N],n,s;
ll p[N];
int main()
{
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;i++) scanf("%d%lld",&x[i],&p[i]);
    int l=1,r=n,op=p[1]>=p[n];
    ll ans=0;
    while(l<=r)
    {
        if(x[l]>s){ans+=x[r]-s;break;}
        if(x[r]<s){ans+=s-x[l];break;}
        if(p[l]>=p[r]) p[l]+=p[r],ans+=op*(x[r]-x[l]),op=0,r--;
        else p[r]+=p[l],ans+=(1-op)*(x[r]-x[l]),op=1,l++;
    }
    printf("%lld\n",ans);
    return 0;
}

E. Inversions

首先考虑 O(n2) 怎么做:

考虑算原序列的一种方法:用 di 表示 aii 的数量,那么 i 可以放在这 di 个位置上,但其中恰好有 ni 个位置已经放了数字,所以总共还剩 di(ni) 个位置。令 di=di(ni),M=di

然后考虑将逆序对分开处理贡献,即考虑 i<j,pi<pj 的方案数。

不妨钦定此时 ai<aj,那么要产生逆序对当且仅当 j 位置的值比 i 小,可以发现这部分等价于 ai=aj,即逆序对数等于总数除以二。但同时所有位于 (ai,aj] 中的数字都会少 1 的答案,所以总方案数就是 Mdi1di

对于 ai>aj 的情况,可以发现就是总方案减去上述方案。

直接枚举 i,j 就是 O(n2)。考虑优化。

可以发现枚举 i,总方案数本质上是一些后缀积的和,所以直接用树状数组维护即可。复杂度 O(nlogn)

注意特判 0。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=200010,mod=1000000007,iv2=(mod+1)/2;
int n;
int ksm(int a,int b=mod-2)
{
    int r=1;
    for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) r=1ll*r*a%mod;
    return r;
}
struct tree_a{
    int a[N];
    void clear(){memset(a,0,sizeof(a));}
    void add(int x,int v){for(;x<=n;x+=(x&-x)) a[x]=(a[x]+v)%mod;}
    int qry(int x){int v=0;for(;x;x-=(x&-x)) v=(v+a[x])%mod;return v;}
    int sum(int l,int r){return (qry(r)-qry(l-1)+mod)%mod;}
}c0,c1;
int a[N],p[N],M=1;
int pre[N],sum[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),p[a[i]]++;
    for(int i=n-1;i;i--) p[i]+=p[i+1];
    for(int i=1;i<=n;i++) p[i]-=n-i,M=1ll*M*p[i]%mod;
    sum[0]=pre[0]=1;
    for(int i=1;i<=n;i++)
    {
        if(p[i]<=1) pre[i]=i,sum[i]=sum[i-1];
        else pre[i]=pre[i-1],sum[i]=1ll*sum[i-1]*(p[i]-1)%mod*ksm(p[i])%mod;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        ans=(ans+1ll*c0.sum(pre[a[i]],a[i])*sum[a[i]]%mod*iv2%mod)%mod;
        c0.add(a[i],ksm(sum[a[i]]));
    }
    c0.clear();
    for(int i=n;i;i--)
    {
        ans=(ans+c1.qry(a[i]-1)-1ll*c0.sum(pre[a[i]],a[i]-1)*sum[a[i]]%mod*iv2%mod+mod)%mod;
        c0.add(a[i],ksm(sum[a[i]]));c1.add(a[i],1);
    }
    ans=1ll*ans*M%mod;
    printf("%d\n",ans);
    return 0;
}

F. 01 on Tree

题解

posted @   Flying2018  阅读(6)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示