积木 [DP+转化]
发现自己越训越菜啥DP都写不出来了。。
感觉这道DP属实有些神仙其实是我属实菜。好像全网都没啥题解的亚子
大意是给出 \(O(2e5)\) 个三元组 \((a,b,c)\) ,值域 \(150\) ,代表组内三种物品的数量。问随意挑出两组,其中物品构成的多重集排列数。
直接列式子全是下降幂跟阶乘,就很难受,拆不开。考虑必要的转化。
两个三元组 \((a_i,b_i,c_i)\) 与 \((a_j,b_j,c_j)\) 构成的多重集排列数从路径计数的角度考虑,就是三维空间内从点 \((-a_i,-b_i,-c_i)\) 走到 \((a_j,b_j,c_j)\) 的方案数。
于是突然就可以DP了。当然枚举两个二元组每次做坐标DP肯定不行。可以合并DP,在每个起点处 \(+1\) ,做一遍DP即可。
最后减去自己与自己构成的方案,再除以 \(2\) 就好了。
God is Madoka
#include<bits/stdc++.h>
using namespace std;
namespace IO{
typedef long long LL;
typedef double DB;
#define int LL
int read(){
int x=0,f=0; char ch=getchar();
while(ch>'9'||ch<'0'){ f|=(ch=='-'); ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return f?-x:x;
} char output[50];
void write(int x,char sp){
int len=0;
if(x<0) putchar('-'), x=-x;
do{ output[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
}
void ckmax(int& x,int y){ x=x>y?x:y; }
void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;
const int NN=200010,mod=1e8+7;
int n,ans,mxa,mxb,mxc,a[NN],b[NN],c[NN],f[310][310][310];
namespace Combinatorics{
int fac[NN],inv[NN];
int qpow(int a,int b=mod-2,int res=1){
for(;b;b>>=1,a=a*a%mod)
if(b&1) res=res*a%mod;
return res;
}
void init(){
fac[0]=inv[0]=1;
for(int i=1;i<=1000;i++) fac[i]=fac[i-1]*i%mod;
inv[1000]=qpow(fac[1000]);
for(int i=999;i;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
} using namespace Combinatorics;
signed main(){
freopen("cyj.in","r",stdin);
freopen("cyj.out","w",stdout);
n=read(); init();
for(int i=1;i<=n;i++){
ckmax(mxa,a[i]=read());
ckmax(mxb,b[i]=read());
ckmax(mxc,c[i]=read());
}
for(int i=1;i<=n;i++) ++f[mxa-a[i]][mxb-b[i]][mxc-c[i]];
for(int i=0;i<=(mxa<<1);i++)
for(int j=0;j<=(mxb<<1);j++)
for(int k=0;k<=(mxc<<1);k++){
if(i) f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;
if(j) f[i][j][k]=(f[i][j][k]+f[i][j-1][k])%mod;
if(k) f[i][j][k]=(f[i][j][k]+f[i][j][k-1])%mod;
}
for(int i=1;i<=n;i++){
ans=(ans+f[mxa+a[i]][mxb+b[i]][mxc+c[i]])%mod;
ans=(ans+mod-fac[a[i]+b[i]+c[i]<<1]*inv[a[i]<<1]%mod*inv[b[i]<<1]%mod*inv[c[i]<<1]%mod)%mod;
}
ans=ans*qpow(2)%mod;
write(ans,'\n');
return 0;
}