一、题目

点此看题

二、题目

首先感谢一下这位大佬的博客,虽然我看不懂您的讲解,但是还是读得懂代码的

思路是 \(\tt jys\) 给我讲明白的,首先我们可以感觉到快速计算它肯定和矩形有关系,也就是满足某种条件的情况一定在某个矩形中,虽然很抽象,但是我们能大概感觉到这道题的核心思路是 乘法原理

要求的是步数,其实相当于方案数加权,在它不太好算的情况下我们来考虑算方案数。我们记录某一维已经走过的步往左最多走了 \(l\)(是负数),往右最多走了 \(r\) ,那么一维暂时不会走出去的位置数量可以表示成可以表示成 \(m[i]=w[i]-r[i]+l[i]\),那么这种情况下不会走出去的方案数是:

\[\sum_{t=0}^{lim}\prod_{i=1}^k m[i]-t\times dt[i]
\]

其中 \(dt[i]\) 是第 \(i\) 维经过一轮的变化量,\(lim\) 是一个上界表示走了 \(lim\) 轮以后再走就出去了,所以只能够枚举到它,现实告诉我们不能枚举轮数,所以必须要优化。从多项式的角度看,我们把轮数当前自变量去推他的多项式

\[\sum_{i=0}^k dp[i]\times\sum_{t=0}^{lim} t^i
\]

\(dp[i]\) 就是把所有 \(-dt[i]\times t+m[i]\) 乘起来得到的多项式系数,我们把 \(t\) 看作了自变量,但是系数是一定的。求系数可以暴力多项式乘法(应该不会有人写 \(\tt fft\)),后面的那个东西是老套路的,你去搜 [TJOI]教科书般的亵渎 就会找到一堆方法,我推荐 \(yyb\) 这种用第二类斯特林数的做法(省选不是考烂了):不会点此看 。这样就很舒服了,算这个方案数是 \(O(k^2)\) 的嗯。

然后我们枚举是第 \(i\) 步走了出去,可以用差分,也就是第 \(i-1\) 步没有走出去的方案数减去第 \(i\) 步走出去的方案数,再乘上 \(i\) 就是消耗的步数。

但是还没有考虑大轮的贡献啊,考虑上面我们的计算方式,其本质是前缀和,在第 \(i\) 轮走出去的方案数会在 \(t\in [0,i)\) 时都被算一遍,所以我们直接算一遍方案数然后乘上 \(n\) 就可以了。

\(\tt Unfortunately,\) 第一轮之内是需要单独讨论的,但只是增加了实现的难度,对整体算法影响不大,时间复杂度 \(O(nk^2)\)

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 15;
const int N = 500005;
const int MOD = 1e9+7;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,k,inv[M],s[M][M],w[M],a[M],dt[M];
int ans,c[N],d[N],l[M],r[M],z[M];
int Abs(int x)
{
if(x>0) return x;
return -x;
}
int walk(int x,int y)//x维上走一步
{
z[x]+=y;
if(l[x]>z[x] || r[x]<z[x])
{
l[x]=min(l[x],z[x]);
r[x]=max(r[x],z[x]);
return 1;
}
return 0;
}
void init(int k)
{
s[0][0]=inv[0]=inv[1]=1;
for(int i=1;i<=k;i++)//第二类斯特林数
for(int j=1;j<=k;j++)
s[i][j]=(s[i-1][j-1]+s[i-1][j]*j)%MOD;
for(int i=2;i<=k+1;i++)
inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
}
int cal(int k,int n)//这里的n其实是开区间
{
int sum=0,C=1;
for(int i=0;i<=k;i++)//C(n,i+1)*i!*s[k][i]
{
C=C*max(0ll,n-i)%MOD;
sum=(sum+C*inv[i+1]%MOD*s[k][i])%MOD;
}
return sum;
}
int work()
{
int lim=MOD,res=0;
for(int i=1;i<=k;i++)
if(dt[i]) lim=min(lim,(a[i]+dt[i]-1)/dt[i]);
int dp[M]={1};
for(int i=1;i<=k;i++)//暴力多项式乘法
for(int j=i;j>=0;j--)
{
dp[j+1]=(dp[j+1]-dt[i]*dp[j])%MOD;
dp[j]=dp[j]*a[i]%MOD;
}
for(int i=0;i<=k;i++)
res=(res+dp[i]*cal(i,lim))%MOD;
return res;
}
signed main()
{
n=read();k=read();
init(k);
for(int i=1;i<=k;i++)
w[i]=read();
for(int i=1;i<=n;i++)
{
c[i]=read();d[i]=read();
if(walk(c[i],d[i]) && r[c[i]]-l[c[i]]<=w[c[i]])
//第二个判断很重要,因为要保证可能在这一步走出去
{
int x=1;
for(int j=1;j<=k;j++)
if(j!=c[i])
x=(x*max(0ll,w[j]-r[j]+l[j]))%MOD;
ans=(ans+i*x)%MOD;//要在这里走出去只有一种选择
}
}
int fl=1;
for(int i=1;i<=k;i++)
{
fl&=(z[i]==0);
dt[i]=Abs(z[i]);//别忘了
}
if(fl==1)
{
for(int i=1;i<=k;i++)
fl|=(r[i]-l[i]>=w[i]);
if(fl) puts("-1");
else printf("%lld\n",ans);
return 0;
}
for(int i=1;i<=k;i++)
a[i]=max(0ll,w[i]-r[i]+l[i]);
ans=(ans+n*work())%MOD;//第一部分贡献
for(int i=1;i<=n;i++)//第二部分贡献
if(walk(c[i],d[i]) && r[c[i]]-l[c[i]]<=w[c[i]])
{
fl=1;
for(int j=1;j<=k;j++)
if(j!=c[i])
fl&=(w[j]-r[j]+l[j]>0);
if(!fl) continue;
for(int j=0;j<k;j++)
if(j!=c[i]) a[j]=max(0ll,w[j]-r[j]+l[j]);
a[c[i]]=w[c[i]]-r[c[i]]+l[c[i]]+1;//差分差分
ans=(ans+i*work())%MOD;
a[c[i]]=w[c[i]]-r[c[i]]+l[c[i]];
ans=(ans-i*work())%MOD;
}
printf("%lld\n",(ans+MOD)%MOD);
}

[NOIP 2020] 微信步数的更多相关文章

  1. 「NOIP 2020」微信步数(计数)

    「NOIP 2020」微信步数(Luogu P7116) 题意: 有一个 \(k\) 维场地,第 \(i\) 维宽为 \(w_i\),即第 \(i\) 维的合法坐标为 \(1, 2, \cdots, ...

  2. 【Redis面试题】如何使用Redis实现微信步数排行榜?

    1. 前言 之前写过一篇博客,讲解的是Redis的5种数据结构及其常用命令,当时有读者评论,说希望了解下这5种数据结构各自的使用场景,不过一直也没来得及写. 碰巧,在3月份找工作面试时,有个面试官先问 ...

  3. 洛谷 P7116 - [NOIP2020] 微信步数(拉格朗日插值)

    洛谷题面传送门 我竟然独立切掉了这道题!incredible! 纪念我逝去的一上午(NOIP 总时长 4.5h,这题做了我整整 4.5h) 首先讲一下现场我想的 80 分的做法,虽然最后挂成了 65 ...

  4. [luogu7116]微信步数

    先判定无解,当且仅当存在一个位置使得移动$n$步后没有结束且仍在原地 暴力枚举移动的步数,记$S_{i}$为移动$i$步(后)未离开范围的点个数,则恰好移动$i$步的人数为$S_{i-1}-S_{i} ...

  5. NOIP 2020 游记

    第一次写比赛游记,请多多指教! I. 考前 由于最近参加了太多太多比赛了,所以没有敲模板题: 考前一周:主要是在做 AtCoder 的题和 xjoi 的模拟赛,相当于恶补了一些套路吧! 考前一天:上午 ...

  6. NOIP 2020 退役记

    躲进你的身体. 哈哈 没想到这么快就轮到我退役啦 以前想想还感觉挺遥远的 这是我最后的机会啦! day-1 晚上照例吃了断头饭 但是没有蛋糕/kk 恭喜 Luckyblock 逃过一劫! (照照片的时 ...

  7. NOIp 2020

    游记 Day-1 我已经开始慌了. 不知道前路如何.不想回文化课.唯一一次机会,可是这几天却一直在颓,不颓就慌. 没心思写题,导致这几天看的题啥都不会.不知道考试当天又会出什么幺蛾子. 啊啊啊,烦. ...

  8. 【Python可视化】超详细Pyecharts 1.x教程,让你的图表动起来~

    前言 pyecharts 是一个用于生成 Echarts 图表的Python库.Echarts是百度开源的一个数据可视化 JS 库,可以生成一些非常酷炫的图表. Pyecharts在1.x版本之后迎来 ...

  9. 2021record

    2021-10-14 P2577 [ZJOI2004]午餐 2021-10-13 CF815C Karen and Supermarket(小小紫题,可笑可笑) P6748 『MdOI R3』Fall ...

随机推荐

  1. [视频] Docker 安装 nginx + rtmp

    目录 拉取镜像 创建并运行容器,映射出两个端口1935.80 将视频文件推流至rtmp服务器 使用ffplay播放rtmp流 拉取镜像 docker pull alfg/nginx-rtmp 创建并运 ...

  2. Redis 事务 & 消息队列

    Redis 消息队列介绍 什么是消息队列 消息队列(Message Queue)是一种应用间的通信方式,消息发送后可以立即返回,有消息系统来确保信息的可靠传递,消息生产者只管把消息发布到消息队列中而不 ...

  3. Linux系统SCSI磁盘扫描机制解析及命令实例

    介绍Linux系统扫描SCSI磁盘有几种方式?Linux新增LUN之后,能否不重启主机就认出设备?如果安装了PowerPath,动态添加/删除LUN的命令是什么?本文总结了Linux主机对磁盘设备进行 ...

  4. leetcode 周赛 205 1576-5508-5509-5510

    第四题比较难,看题解用并查集做比较简单,但是我觉得难度在想到用并查集,可能是最近做题少所以想不到吧. 1 替换所有的问号 class Solution { public: string modifyS ...

  5. QXDM和QCAT软件使用指南

    一.传送门 链接:https://pan.baidu.com/s/1i55YXnf 密码:v6nw 二.QXDM,QPST和QCAT的简单说明 QXDM,QPST和QCAT是Qualcomm高通公司针 ...

  6. Pygame 游戏开发 All In One

    Pygame 游戏开发 All In One Pygame Pygame is a library for digital arts, games, music, making, and a comm ...

  7. Sentry & React

    Sentry & React https://docs.sentry.io/platforms/javascript/guides/react/ https://docs.sentry.io/ ...

  8. React Security Best Practices All In One

    React Security Best Practices All In One Default XSS Protection with Data Binding Dangerous URLs Ren ...

  9. React Toolchains

    React Toolchains Create React App / component library https://create-react-app.dev/docs/getting-star ...

  10. js spider

    js spider https://gist.github.com/xgqfrms-GitHub/0bf82ff06037a0d1776c9f30033cbfd1 https://www.cnblog ...