传送门:QAQQAQ

题意:话说小X在孩提时,都会做标准的蛇形矩阵了,发现很好玩。现在的小X很想对其进行改版,变为如下类型的一个无限大蛇形数阵:

令S(x)表示以1为左上角,x为右下角的矩形内所有数之和。例如S(12)就是具有深色背景的数之和。
给定n,对于“以1为左上角,n为右下角的矩形”内的每一个数i,计算所有S(i)之和。

思路:神仙数学题。。。

先看暴力:我们通过人工YY和简单推算可以得出一个公式:$ans=\sum_{i=1}^{n}\sum_{j=1}^{m}a_{i,j}*\left ( n-i+1 \right )*\left ( m-j+1 \right )$

那么我们可以在$O(n)$的复杂度内解决问题

现在开始优化环节:我们可以把一个给定矩形拆分成若干条链,使每一条链都是一个连续的数列(莫名想到树链剖分。。。)

具体拆分方法为:若是一个长方形,则先把多余的行或列拆出来,把它变成一个正方形。然后对于每一圈,我们先竖着拆$rnd$个,再横着拆$rnd-1$个,拆完为止。

现在我们的任务是求一个连续序列的和。每一个的统计总和为$a_{i,j}*\left ( n-i+1 \right )*\left ( m-j+1 \right )$,而且这个序列一定在同一行或同一列,所以我们可以把$\left ( n-i+1 \right )$或$\left ( m-j+1 \right )$中的一项提取出来,这样剩下的就是两项相乘求和了。而我们发现这两项分别在两个公差为$1$或$-1$的等差数列中。

现在开始数学环节——暴力推公式

令$f(s1,s2,d1,d2,n)$为首项为$s1$,公差为$d1$的等差数列和首项为$s2$,公差为$d2$的等差数列每一项分别相乘,前$n$项乘积的和

即:$f(s1,s2,d1,d2,n)$=$\sum_{i=1}^{n}\left [ s1+\left ( i-1 \right )*d1 \right ]*\left [ s2+\left ( i-1 \right )*d2 \right ]$

          =$\sum_{i=1}^{n}(s1*s2)+\sum_{i=1}^{n}(s1*d2*(i-1))+\sum_{i=1}^{n}( d1*s2*(i-1))+\sum_{i=1}^{n}( d1*d2*(i-1)^{2} )$

          =$n*s1*s2+s1*d2*\sum_{i=1}^{n-1}i+s2*d1*\sum_{i=1}^{n-1}i+d1*d2*\sum_{i=1}^{n-1}i^{2}$

          =$n*s1*s2+s1*d2*\frac{(n-1)*n}{2}+d1*s2*\frac{(n-1)*n}{2}+d1*d2*\frac{(n-1)*n*(2*n-1)}{6}$

那么我们现在就可以用$O(1)$的时间算出每一条链,而一共拆成$\sqrt{n}$条链,所以总复杂度$\sqrt{n}$

代码:(注意代码实现时$x,y$很容易弄混)

#include<bits/stdc++.h>
#define pii pair<ll,ll>
#define mk make_pair
using namespace std;
typedef long long ll;
const ll MOD=(ll)1e9+;
const ll inv2=;
const ll inv6=; pii find(ll x)
{
ll rnd=(ll)sqrt(x);
if(rnd*rnd!=x) rnd++;
ll End=rnd*rnd;
ll dif=End-x;
ll posx,posy;
if(rnd%==)
{
posx=rnd; posy=;
if(dif<=rnd-) posy+=dif;
else
{
posy=rnd; dif-=(rnd-);
posx-=dif;
}
}
else
{
posx=,posy=rnd;
if(dif<=rnd-) posx+=dif;
else
{
posx=rnd; dif-=(rnd-);
posy-=dif;
}
}
return mk(posx,posy);
} void fn(ll &x)
{
x=(x%MOD+MOD)%MOD;
} ll f(ll s1,ll s2,ll d1,ll d2,ll n)
{
if(n==) return ;
ll ret=n*s1%MOD*s2%MOD; fn(ret);
ret=(ret+n*(n-)%MOD*inv2%MOD*(s1*d2%MOD+s2*d1%MOD))%MOD; fn(ret);
ret=(ret+n*(n-)%MOD*(*n-)%MOD*inv6%MOD*d1%MOD*d2%MOD); fn(ret);
return ret;
} int main()
{
ll x,ans=;
scanf("%lld",&x);
pii pos=find(x);
ll n=pos.first,m=pos.second;
ll nowx=n,nowy=m;
while(nowx>m)
{
if(nowx%==)
{
ll k=n-nowx+;
ll s1=(nowx-)*(nowx-)+; ll d1=;
ll s2=m; ll d2=-;
ans=(ans+k*f(s1,s2,d1,d2,m))%MOD;
}
else
{
ll k=n-nowx+;
ll s1=nowx*nowx; ll d1=-;
ll s2=m; ll d2=-;
ans=(ans+k*f(s1,s2,d1,d2,m))%MOD;
}
nowx--;
}
while (nowy>n)
{
if(nowy%==)
{
ll k=m-nowy+;
ll s1=nowy*nowy; ll d1=-;
ll s2=n; ll d2=-;
ans=(ans+k*f(s1,s2,d1,d2,n))%MOD;
}
else
{
ll k=m-nowy+;
ll s1=(nowy-)*(nowy-)+; ll d1=;
ll s2=n; ll d2=-;
ans=(ans+k*f(s1,s2,d1,d2,n))%MOD;
}
nowy--;
}
while(nowx>&&nowy>)
{
if(nowx%==)
{
ll k=m-nowy+;
ll s1=nowy*nowy; ll d1=-;
ll s2=n; ll d2=-;
ans=(ans+k*f(s1,s2,d1,d2,nowx))%MOD;
k=n-nowx+;
s1=(nowx-)*(nowx-)+; d1=;
s2=m; d2=-;
ans=(ans+k*f(s1,s2,d1,d2,nowy-))%MOD;
}
else
{
ll k=m-nowy+;
ll s1=(nowy-)*(nowy-)+; ll d1=;
ll s2=n; ll d2=-;
ans=(ans+k*f(s1,s2,d1,d2,nowx))%MOD;
k=n-nowx+;
s1=nowx*nowx; d1=-;
s2=m; d2=-;
ans=(ans+k*f(s1,s2,d1,d2,nowy-))%MOD;
}
nowx--; nowy--;
}
cout<<ans<<endl;
return ;
}

夏令营501-511NOIP训练17——蛇形矩阵的更多相关文章

  1. XJOI 夏令营501-511NOIP训练17 蛇形数阵

    话说小X在孩提时,都会做标准的蛇形矩阵了,发现很好玩.现在的小X很想对其进行改版,变为如下类型的一个无限大蛇形数阵:令S(x)表示以1为左上角,x为右下角的矩形内所有数之和.例如S(12)就是具有深色 ...

  2. EOJ3536 求蛇形矩阵每一行的和---找规律

    题目链接: https://acm.ecnu.edu.cn/problem/3536/ 题目大意: 求蛇形矩阵的每一行的和,数据范围n<=200000. 思路: 由于n数据较大,所以感觉应该是需 ...

  3. EOJ 3.30 B. 蛇形矩阵【找规律/待补】

    [链接]:https://acm.ecnu.edu.cn/contest/59/problem/B/ B. 蛇形矩阵 Time limit per test: 2.0 seconds Memory l ...

  4. js实现蛇形矩阵

    参加腾讯前端实习生笔试,真的是被虐了千百遍,除了一条js程序题,其他半点前端都没有,都是考算法,计算机原理,数据结构.下面贴上腾讯笔试最后三大条中的一条,实现一个蛇形矩阵的输出.蛇形矩阵的什么样这里我 ...

  5. 【面试】输出"蛇形"矩阵

    一.题目描述 腾讯实习在线笔试的一道题目. 根据输入的数字(< 1000),输出这样的"蛇形"矩阵,如下.输入n,输出(n * n)阶矩阵,满足由外到内依次增大. 如: 输入 ...

  6. c++实现蛇形矩阵总结

    蛇形矩阵,百度了一下,是这么一个东西: 像一条蛇一样依次递增. 我想,竟然做了螺旋矩阵,那做一下这个吧.在之前的螺旋矩阵的main函数基础上,写个函数接口就行了,这一次做的很快,但是这个矩阵感觉比螺旋 ...

  7. wikioi 1160 蛇形矩阵

    /*======================================================================== 1160 蛇形矩阵 题目描述 Descriptio ...

  8. Java编码 蛇形矩阵的构建与遍历输出

    一.蛇形矩阵的构建,并按行输出 例: 输入:n, 生成n*n的蛇形矩阵 1 2 3 8 9 4 7 6 5 输出:1 2 3 8 9 4 7 6 5 java编码 public static void ...

  9. c++打印蛇形矩阵

    一个m*n的矩阵里按照下图形式填充,最后形成的矩阵即为蛇形矩阵,下图是m=4, n =5时的蛇形矩阵: 方法一:逐层循环 #include <iostream> using namespa ...

随机推荐

  1. 第二天:PowerShell别名

    1.查询别名: Get-Alias -name ls Get-Alias -name dir Get-Alias -name fl Get-Alias -name ft 2.查看可用的别名 查看可用的 ...

  2. laravel 关掉debug

    修改.env文件 APP_DEBUG=false 然后把Laravel服务重启一下

  3. redis主从和集群搭建

    主从搭建 redis的主从搭建非常简单,打开配置文件6379.conf,只需要将主节点的protected-mode设置为no,然后在从节点配置中加入:slaveof <masterip> ...

  4. leetcood学习笔记-167-两数之和 II - 输入有序数组

    题目描述: 第一次提交: class Solution(object): def twoSum(self, numbers, target): """ :type num ...

  5. JUC 一 FutureTask

    java.util.concurrent public class FutureTask<V> implements RunnableFuture<V> 简介 FutureTa ...

  6. DELPHI 让子窗体显示在任务栏上

    重载 CreateParams 方法即可 声明: procedure CreateParams(var Params: TCreateParams);override; procedure TForm ...

  7. NX二次开发-创建圆弧(起点-终点-半径)UF_CURVE_create_arc_point_point_radius

    NX9+VS2012 #include <uf.h> #include <uf_curve.h> UF_initialize(); //起点 ]; ArcStartPoint[ ...

  8. NX二次开发-对话框解锁UF_UI_unlock_ug_access

    VC/MFC调用UG Dialog要进入加锁状态 加锁 UF_UI_lock_ug_access ( UF_UI_FROM_CUSTOM ); 此处为UF_UI_select的函数 解锁 UF_UI_ ...

  9. Delphi中文件名函数-路径、名称、子目录、驱动器、扩展名

    文件名函数 文件名函数可以对文件的名称.所在子目录.驱动器和扩展名等进行操作.下表列出这些函数及其功能. 函数说明 ExpandFileName() //返回文件的全路径(含驱动器.路径) Extra ...

  10. Apache Shiro RememberMe 1.2.4 反序列化漏洞

    拉取镜像 docker pull medicean/vulapps:s_shiro_1 启动环境 docker run -d -p 80:8080 medicean/vulapps:s_shiro_1 ...