夏令营501-511NOIP训练17——蛇形矩阵
传送门: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——蛇形矩阵的更多相关文章
- XJOI 夏令营501-511NOIP训练17 蛇形数阵
话说小X在孩提时,都会做标准的蛇形矩阵了,发现很好玩.现在的小X很想对其进行改版,变为如下类型的一个无限大蛇形数阵:令S(x)表示以1为左上角,x为右下角的矩形内所有数之和.例如S(12)就是具有深色 ...
- EOJ3536 求蛇形矩阵每一行的和---找规律
题目链接: https://acm.ecnu.edu.cn/problem/3536/ 题目大意: 求蛇形矩阵的每一行的和,数据范围n<=200000. 思路: 由于n数据较大,所以感觉应该是需 ...
- EOJ 3.30 B. 蛇形矩阵【找规律/待补】
[链接]:https://acm.ecnu.edu.cn/contest/59/problem/B/ B. 蛇形矩阵 Time limit per test: 2.0 seconds Memory l ...
- js实现蛇形矩阵
参加腾讯前端实习生笔试,真的是被虐了千百遍,除了一条js程序题,其他半点前端都没有,都是考算法,计算机原理,数据结构.下面贴上腾讯笔试最后三大条中的一条,实现一个蛇形矩阵的输出.蛇形矩阵的什么样这里我 ...
- 【面试】输出"蛇形"矩阵
一.题目描述 腾讯实习在线笔试的一道题目. 根据输入的数字(< 1000),输出这样的"蛇形"矩阵,如下.输入n,输出(n * n)阶矩阵,满足由外到内依次增大. 如: 输入 ...
- c++实现蛇形矩阵总结
蛇形矩阵,百度了一下,是这么一个东西: 像一条蛇一样依次递增. 我想,竟然做了螺旋矩阵,那做一下这个吧.在之前的螺旋矩阵的main函数基础上,写个函数接口就行了,这一次做的很快,但是这个矩阵感觉比螺旋 ...
- wikioi 1160 蛇形矩阵
/*======================================================================== 1160 蛇形矩阵 题目描述 Descriptio ...
- 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 ...
- c++打印蛇形矩阵
一个m*n的矩阵里按照下图形式填充,最后形成的矩阵即为蛇形矩阵,下图是m=4, n =5时的蛇形矩阵: 方法一:逐层循环 #include <iostream> using namespa ...
随机推荐
- zepto-touch事件
<!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...
- python编程语言学习day05(1)
模块(不起与python相关模块的名字) 1.random random.random() 在0与1之间取随机数 random.randint(a,b) 在a,b之间取随机整数,包括边界 ra ...
- leetcode-52-N皇后②
题目描述: 方法一:回溯 class Solution: def totalNQueens(self, n: int) -> int: def backtrack(i,tmp,col,z_dia ...
- leetcode-685-冗余连接②
题目描述: 参考后提交:并查集: class Solution: def findRedundantDirectedConnection(self, edges: List[List[int]]) - ...
- Servlet(Server Applet) 详解
Java编写的服务器端程序.其主要功能在于交互式地浏览和修改数据,生成动态Web内容. Servlet的工作模式 客户端发送请求至服务器 服务器启动并调用Servlet,Servlet根据客户端请求生 ...
- C++之判断字符串是否是数字
文章转载自https://blog.csdn.net/Richard__Ting/article/details/80772174 判断是否为数字 #include <iostream> ...
- 牛客多校第六场 D move 枚举/机智题
题意: 有个家伙装东西,他的策略是贪心,每次装进去这个盒子能装下的最大的东西,直到把这个盒子装满,再去装下一个盒子. 给出盒子的数量k和一些东西的重量,问你最小需要多大的盒子才能以这种贪心策略装下. ...
- (转)poi操作Excel, 各种具体操作和解释
原文地址http://hi.baidu.com/j_changhong/item/981fa58d05fa755926ebd96b注原文是3.6 此文是3.9 java读取excel文件的顺序是: E ...
- openstack nova 源码解析 — Nova API 执行过程从(novaclient到Action)
目录 目录 Nova API Nova API 的执行过程 novaclient 将 Commands 转换为标准的HTTP请求 PasteDeploy 将 HTTP 请求路由到具体的 WSGI Ap ...
- 普通用户授予root权限
开始用linux的时候会遇到用户权限问题,比如安装软件的时候经常会提示权限不足,下面介绍给普通用户授予root权限. 找到 cd /etc/sudoers可以看到用户的权限是:只有读取的权限(以下操 ...