zoukankan      html  css  js  c++  java
  • [NOIP2016PJ]魔法阵

    今天模拟赛的题,,,唯一没有Giao出来的题(不然我就AKIOI了~)

    最开始没想到数学题,把所有部分分都说一遍吧:

    35分:纯暴力O(M^4)枚举,对于每一组a,b,c,d验证其是否合法。

    60分:经过读题,不难发现a,b,c,d单调递增,可以考虑对其进行排序后再暴力枚举,枚举量减少近一半。

    85分:对xb-xa=2(xd-xc)进行分析,可以得到以下公式:double((xb-xa+2xc)/2)=double(xd),再查找是否存在xd,这样我们只需枚举a,b,c,时间复杂度是O(M^3)

    100分:依旧是对xb-xa=2(xd-xc)进行分析,我们设t=xd-xc,则xb-xa=2⋅t;再分析第二个条件Xb−Xa<(Xc−Xb)/3,我们可以得到Xc−Xb>6⋅t,我们给他补全成等号,就是Xc−Xb=6⋅t+k

    所以这四个数在数轴上的排列如图所示(图片来自博客园

    所以我们会有一个不成熟的思路:在1-n/9范围内枚举t,把a,b,c,d拿t表示出来。

    那么如何计算呢?枚举D。当我们枚举到一个D值的时候,与之对应的C值是确定的(不受k影响),而A值和B值却不一定。因此我们可以找到最大的与之对应的A值B值。

    但是有可能会存在一组AB值要比当前计算到的小,怎么办呢?不妨设有可能存在的比最大值小的A值为A1,B值为B1,计算到的为A2和B2

    当A1<A2&&B1<B2时,只要A2和B2能组成魔法阵,A1和B1一定可以(k只是大于0的数,而对k的上界没有限制,当我们把k放大时,就可以构造出A1和B1了)。

    由于是顺序枚举,所以我们可以记录一下之前有多少组合法解(类似于前缀和),最后再用乘法原理计算。同样的方法,我们从A的上界往A的下界枚举记录后缀和然后计算即可。

    下面给出参考代码:

     1 // luogu-judger-enable-o2
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #define N 50005
     6 #define M 50005
     7 using namespace std;
     8 int n,m,ans[M][10],num[M],a[M],A,B,C,D;
     9 int read()
    10 {
    11     int x=0,f=1;char ch=getchar();
    12     while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();}
    13     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    14     if(f)return x;return -x;
    15 }
    16 int main()
    17 {
    18     n=read();m=read();
    19     for(int i=1;i<=m;i++)
    20     {
    21         a[i]=read();
    22         num[a[i]]++;
    23     }
    24     for(int t=1;t*9<n;t++)
    25     {
    26         int sum=0;
    27         for(D=9*t+2;D<=n;D++)
    28         {
    29             C=D-t;
    30             B=C-6*t-1;
    31             A=B-2*t;
    32             sum+=num[A]*num[B];
    33             ans[C][3]+=num[D]*sum;
    34             ans[D][4]+=num[C]*sum;
    35         }
    36         sum=A=B=C=D=0;
    37         for(A=n-t*9-1;A>=1;A--)
    38         {
    39             B=A+2*t;
    40             C=B+6*t+1;
    41             D=C+t;
    42             sum+=num[C]*num[D];
    43             ans[A][1]+=num[B]*sum;
    44             ans[B][2]+=num[A]*sum;
    45         }
    46     }
    47     for(int i=1;i<=m;i++)
    48     {
    49         for(int j=1;j<=4;j++)
    50         {
    51             cout<<ans[a[i]][j]<<" ";
    52         }
    53         cout<<endl;
    54     }
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    获取浏览器当前宽高
    获取当前页面一个 CSS 像素与一个物理像素之间的比率
    获取对象的所有属性,不管是否可遍历,不管是自身的还是原型链上的
    获取当前页面内所有框架窗口
    获取当前页面视口(viewport)宽高
    获取当前嵌入窗口所在的那个元素节点
    获取当前页面内框架窗口的数量
    获取窗口顶层对象
    获取当前窗口访问过的页面的数量
    获取`script`标签中的代码内容
  • 原文地址:https://www.cnblogs.com/szmssf/p/11266905.html
Copyright © 2011-2022 走看看