您的位置:首页 > 其它

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

2017-08-15 21:25 253 查看

题目描述



题目分析

这一道题就是一个前缀和与后缀和的问题。

如果我们已经确定了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][1−4]为魔法值为i的点分别作为A~D点的方案数。

那么有以下公式:

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

ans[j+2∗i][1]=ans[j+2∗i][1]+w[j]∗a[j+8∗i+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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: