ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

noip 模拟 y

2021-10-17 09:02:00  阅读:136  来源: 互联网

标签:ch noip int 中选 小球 lim 模拟 define


很考验观察力的一道题
首先发现,若每个人都给左边人小球,那每个人给的小球数就可以都减去一
形式化的,我们只需要考虑存在一个人给的小球数为零的情况
还是按套路来
可以把式子组合意义化(组合意义化后式子总会好推很多)
其实就是每个人从剩下的小球中选一个的总方案
此时选球的情况只有两种:

  • 从原来剩下的小球中选 (设为情况 0 )
  • 从右边的人给的球中选 (设为情况 1 )

那就可以给每个人定义两次分别表示上面的两种情况
又因为是环,转移结束的话我们是需要知道 1 号的选球情况的
那我们可以倾定 1 号的选球情况,最后从该情况索取我们要的答案就好了
那回到初始
我们考虑的仅是存在一个人给的小球数为零的情况
直接用所有情况减去全部给小球的情况就好了
最后考虑两人之间的转移

\(f_{i-1,1}->f_{i,0}\)
它的实际意义是第 \(i-1\) 个人已经选好了
第 \(i\) 个人准备从自己剩下的小球中选,是不考虑 \(i-1\) 给的小球的
但因为 \(i-1\) 给的小球会影响情况数,所以

\[f_{i,0}+=f_{i-1,1}(a_{i-1}-(lim)+1) \]

\(f_{i-1,0}->f_{i,0}\)
\(i-1\) 要从自己剩下的小球中选,\(i\) 也要从自己剩下的小球中选,但只能计算 \(i-1\) 的贡献

\[f_{i,0}+=f_{i-1,0}\sum_{k=0}^{a_{i-1}-(lim)}k \]

\(f_{i-1,1}->f_{i,1}\)
\(i-1\) 已经计算过贡献,\(i\) 要从 \(i-1\) 给的球中选

\[f_{i,1}+=f_{i-1,1}\sum_{k=(lim)}^{a_{i-1}}k \]

\(f_{i-1,0}->f_{i,1}\)
\(i-1\) 的贡献和 \(i\) 的贡献都在这次计算
则:

\[f_{i,1}+=f_{i-1,0}\sum_{k=(lim)}^{a_{i-1}}k(a_{i-1}-k) \]

对于转移方程中的 \((lim)\) 即为你倾定的总限,最后记得容斥

Code
#include <bits/stdc++.h>
#define re register
#define db double
#define int long long
// #define ll long long
#define fr first
#define sc second
#define pb push_back
#define fail { puts("No"); continue; }
#define pir make_pair
#define F(i,a,b) for(re int i=a;i<=b;++i)
#define D(i,a,b) for(re int i=a;i>=b;--i)
#define E(i,a) for(re int i=head[a];i;i=edge[i].nxt)
using namespace std;
const int maxn=3E7+10;
const int INF=1e9+10;
const int LS=1e5;
const int mol=1e9+7;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
inline int read(){
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9') w=(ch=='-')?-1:1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*w;
}

int n,a[1000010],f[2][1000010],inv2=qpow(2,mol-2),inv6=qpow(6,mol-2);
inline int sum(int n) { return ((n+1)%mol*n%mol*inv2%mol)%mol; }
inline int sm(int n) { return (n%mol*(n+1)%mol*(2*n%mol+1)%mol)*inv6%mol; }
inline int ls(int k1,int k2) {
    f[k1][1]=1; f[k1^1][1]=0;
    for(re int i=1,nt;i<=n;i++) {
        nt=(i==n)? 1:i+1;
        f[0][nt]=(f[1][i]*((a[i]-k2+1)%mol)%mol+f[0][i]*sum(a[i]-k2)%mol)%mol;
        f[1][nt]=(f[1][i]*sum(a[i])%mol+(f[0][i]*(a[i]*sum(a[i])%mol-sm(a[i]))%mol)%mol)%mol;
    }
    return f[k1][1];
}
signed main(void) {
    freopen("y.in","r",stdin); freopen("y.out","w",stdout);
    n=read(); for(re int i=1;i<=n;i++) a[i]=read();
    int ans=ls(1,0)+ls(0,0)-ls(1,1)-ls(0,1);
    printf("%lld\n",(ans%mol+mol)%mol);
}

标签:ch,noip,int,中选,小球,lim,模拟,define
来源: https://www.cnblogs.com/zjxlm/p/15415903.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有