2105. 【NOIP2016普及组复赛】魔法阵

博客介绍了NOIP2016普及组复赛中一道关于魔法阵的题目,重点解析了如何利用前缀和与后缀和的方法解决CD点对的方案数问题。通过确定A、B物品,进一步探讨求解ABCD四个物品组合方案的策略,并给出了相关计算公式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

这里写图片描述

题目分析

这一道题就是一个前缀和与后缀和的问题。
如果我们已经确定了A物品和B物品,我们该怎样知道组成ABCD四个物品的方案数呢?
我们只要求另外两个CD点对的方案数就行了。
我们假设sum[i]为从第i个点到第n个点的CD点对方案数,那公式就是:

sum[j]=sum[j+1]+w[j]w[j+i]

其中j是枚举1~n的点,而i是枚举CD距离,w[i]是指魔法值为i的物品数。
我们又假设ans[i][14]为魔法值为i的点分别作为A~D点的方案数。
那么有以下公式:
ans[j][0]=ans[j][0]+w[j+2i]a[j+8i+1];

ans[j+2i][1]=ans[j+2i][1]+w[j]a[j+8i+1];

其中k是枚举点A的位置。
接着我们又反过来做,找出CD点方案数即可。

代码

#include<cstdio>
#include<cstring>
using namespace std;
int w[16000];
int ans[16000][4];
int a[16000],b[16000],c[41000];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        w[x]++;
        c[i]=x;
    }
    for(int i=1;i<=(n-1)/9;i++)
    {
        a[n-i+1]=0;
        for(int j=n-i;j>=1;j--)
        {
            a[j]=a[j+1]+w[j]*w[j+i];
        }
        for(int j=1;j<=n-1-8*i;j++)
        {
            ans[j][0]+=w[j+2*i]*a[j+8*i+1];
            ans[j+2*i][1]+=w[j]*a[j+8*i+1];
        }
        b[0]=0;
        for(int j=1;j<=n-2*i;j++)
        {
            b[j]=b[j-1]+w[j]*w[j+2*i];
        }
        for(int j=8*i+2;j<=n;j++)
        {
            ans[j][2]+=w[j+i]*b[j-8*i-1];
            ans[j+i][3]+=w[j]*b[j-8*i-1];
        }
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d %d %d %d\n",ans[c[i]][0],ans[c[i]][1],ans[c[i]][2],ans[c[i]][3]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值