1. 程式人生 > >2105. 【NOIP2016普及組複賽】魔法陣

2105. 【NOIP2016普及組複賽】魔法陣

題目描述

這裡寫圖片描述

題目分析

這一道題就是一個字首和與字尾和的問題。
如果我們已經確定了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; }