很考验观察力的一道题
首先发现,若每个人都给左边人小球,那每个人给的小球数就可以都减去一
形式化的,我们只需要考虑存在一个人给的小球数为零的情况
还是按套路来
可以把式子组合意义化(组合意义化后式子总会好推很多)
其实就是每个人从剩下的小球中选一个的总方案
此时选球的情况只有两种:
- 从原来剩下的小球中选 (设为情况 0 )
- 从右边的人给的球中选 (设为情况 1 )
那就可以给每个人定义两次分别表示上面的两种情况
又因为是环,转移结束的话我们是需要知道 1 号的选球情况的
那我们可以倾定 1 号的选球情况,最后从该情况索取我们要的答案就好了
那回到初始
我们考虑的仅是存在一个人给的小球数为零的情况
直接用所有情况减去全部给小球的情况就好了
最后考虑两人之间的转移
\(f_{i-1,1}->f_{i,0}\)
它的实际意义是第 \(i-1\) 个人已经选好了
第 \(i\) 个人准备从自己剩下的小球中选,是不考虑 \(i-1\) 给的小球的
但因为 \(i-1\) 给的小球会影响情况数,所以
\(f_{i-1,0}->f_{i,0}\)
\(i-1\) 要从自己剩下的小球中选,\(i\) 也要从自己剩下的小球中选,但只能计算 \(i-1\) 的贡献
\(f_{i-1,1}->f_{i,1}\)
\(i-1\) 已经计算过贡献,\(i\) 要从 \(i-1\) 给的球中选
\(f_{i-1,0}->f_{i,1}\)
\(i-1\) 的贡献和 \(i\) 的贡献都在这次计算
则:
对于转移方程中的 \((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);
}