diyiti
直接考虑把
n
n
n质因数分解,然后就是一个套路的容斥。
其实可以二进制压位枚举集合然后枚举其子集求容斥系数但能写dfs鬼才写那玩意儿
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int mod=998244353;
typedef long long ll;
typedef pair<int,int> pii;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:a-=mod;}
inline void Dec(int&a,int b){(a-=b)<0?a+=mod:a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
inline ll mul(ll a,ll b,ll md){return a*b-(ll)((long double)a*b/md)*md;}
inline ll ksm(ll a,ll p,ll md){ll ret=1;for(;p;p>>=1,a=mul(a,a,md))if(p&1)ret=mul(ret,a,md);return ret;}
int pri[14]={3,5,7,11,13,17,19,23,29,31,37,41,43,47};
inline bool test(int a,ll x,ll t,int s){
if(ksm(a,x-1,x)!=1)return 0;
ll f=ksm(a,t,x),pre=f;
for(ri i=0;i<s;++i){
f=mul(f,f,x);
if(f==1&&pre!=1&&pre!=x-1)return 0;
pre=f;
}
return 1;
}
inline bool miller_rabin(ll x){
if(!(x&1))return x==2;
ll t=x-1,s=0;
while(!(t&1))t>>=1,++s;
for(ri i=0;i<14;++i){
if(x==pri[i])return 1;
if(x==x/pri[i]*pri[i])return 0;
if(!test(pri[i],x,t,s))return 0;
}
return 1;
}
const int N=35;
int a[N],tot=0,ans=0;
ll n;
inline void update(int c1,int c2,bool coe){int t=mul(c2,ksm(2,c1)-1);coe?Add(ans,t):Dec(ans,t);}
void dfs(int pos,int c1,int c2,bool coe){
if(pos==tot+1)return update(c1,c2,coe);
dfs(pos+1,mul(c1,a[pos]+1,mod-1),c2,coe);
dfs(pos+1,mul(c1,a[pos],mod-1),mul(c2,2),coe^1);
if(a[pos]^1)dfs(pos+1,mul(c1,a[pos]-1,mod-1),c2,coe);
}
inline void init(){
for(ri i=2,up=min((ll)sqrt(n),1000000ll);i<=up;++i){
if(n!=n/i*i)continue;
++tot;
while(n==n/i*i)++a[tot],n/=i;
}
if(n^1){
if(miller_rabin(n))a[++tot]=1;
else{
ll t=sqrt(n);
if(n==t*t)a[++tot]=2;
else a[++tot]=1,a[++tot]=1;
}
}
}
int main(){
#ifdef ldxcaicai
freopen("lx.in","r",stdin);
#endif
cin>>n;
init();
dfs(1,1,1,1);
cout<<ans;
return 0;
}
dierti
设 f i , j , k f_{i,j,k} fi,j,k表示已经决定完前 i i i种的状态,前 i i i种总共选了 j j j张,且 max { c o l l e c t i n g i − c i , 0 } − max { c o l l e c t i n g i − c i , 0 } 4 = k \max\{collecting_i-c_i,0\}-\frac{\max\{collecting_i-c_i,0\}}4=k max{collectingi−ci,0}−4max{collectingi−ci,0}=k的不考虑不同颜色间顺序时的期望。
然后可以枚举第 i i i张选几张,注意到 k ≤ 0 k\le0 k≤0时就不用转移了。
然后假设最后各邮票的选取个数为
a
1
,
a
2
,
.
.
.
,
a
k
a_1,a_2,...,a_k
a1,a2,...,ak,那么考虑不同颜色间顺序的方案数为
(
a
1
+
a
2
+
⋅
⋅
⋅
+
a
n
)
!
a
1
!
a
2
!
a
3
!
.
.
.
a
n
!
\frac{(a_1+a_2+\cdot\cdot\cdot+a_n)!}{a_1!a_2!a_3!...a_n!}
a1!a2!a3!...an!(a1+a2+⋅⋅⋅+an)!
我们的
d
p
dp
dp只能保留
a
1
+
a
2
+
⋅
⋅
⋅
+
a
n
a_1+a_2+\cdot\cdot\cdot+a_n
a1+a2+⋅⋅⋅+an的值,因此
a
i
!
a_i!
ai!这个系数要在
d
p
dp
dp的时候加进去。
然后这题
d
p
dp
dp时的边界条件极其神奇。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
bool f=1;
char ch=gc();
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return f?ans:-ans;
}
const int mod=1e9+7;
typedef long long ll;
inline int add(int a,int b){return (a+=b)<mod?a:a-mod;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline void Add(int&a,int b){(a+=b)<mod?a:a-=mod;}
inline void Dec(int&a,int b){(a-=b)<0?a+=mod:a;}
inline void Mul(int&a,int b){a=(ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,Mul(a,a))if(p&1)Mul(ret,a);return ret;}
const int N=1605;
int n,q[105],cur=0,a[105],fac[N],ifac[N],f[11][1605][405],p[1605];
inline void init(int up=1600){
fac[0]=fac[1]=ifac[0]=ifac[1]=1;
for(ri i=2;i<=up;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
for(ri i=2;i<=up;++i)Mul(ifac[i],ifac[i-1]);
}
int main(){
#ifdef ldxcaicai
freopen("lx.in","r",stdin);
#endif
init();
n=read();
int sum=0;
for(ri i=1;i<=n;++i)sum+=(q[i]=read());
sum=ksm(sum,mod-2);
for(ri i=1;i<=n;++i)Mul(q[i],sum);
sum=0;
for(ri i=1;i<=n;++i)sum+=(a[i]=read());
f[0][0][sum]=1;
sum<<=2;
for(ri t,i=1,pre=0;i<=n;++i,pre=sum){
for(ri mt=1,j=0;j<=sum;++j,Mul(mt,q[i]))p[j]=mul(ifac[j],mt);
for(ri trans,j=0;j<=sum;++j)for(ri k=1;k<=400;++k)if((trans=f[i-1][j][k]))
for(ri tt,l=0,up=sum-j;l<=up;++l){
tt=((l<a[i])?(l-a[i]):(l-a[i])/4)+a[i];
if(k<=tt)break;
(f[i][j+l][k-tt]+=(ll)p[l]*trans%mod)%=mod;
}
}
int ans=1;
for(ri t=0,i=1;i<=sum;++i,t=0){
for(ri j=1;j<=400;++j)Add(t,f[n][i][j]);
Add(ans,mul(fac[i],t));
}
cout<<ans;
return 0;
}
disanti
考虑最后最优解一定满足前两个限制,只需最大化距离和即可。
由于
x
,
y
x,y
x,y坐标对称因此可以只考虑
x
x
x坐标的信息。
Δ
=
∑
i
,
j
(
x
i
+
a
i
−
x
j
−
a
j
)
2
−
(
x
i
−
x
j
)
2
=
∑
i
,
j
(
a
i
−
a
j
)
2
+
2
(
x
i
−
x
j
)
(
a
i
−
a
j
)
=
C
+
2
n
∑
i
x
i
a
i
\begin{aligned}\Delta=&\sum_{i,j}(x_i+a_i-x_j-a_j)^2-(x_i-x_j)^2\\=&\sum_{i,j}(a_i-a_j)^2+2(x_i-x_j)(a_i-a_j)\\=&C+2n\sum_{i}x_ia_i\end{aligned}
Δ===i,j∑(xi+ai−xj−aj)2−(xi−xj)2i,j∑(ai−aj)2+2(xi−xj)(ai−aj)C+2ni∑xiai
那么做一个最大权匹配即可
然而要写bfs版的才能过
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
bool f=1;
char ch=gc();
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return f?ans:-ans;
}
typedef pair<int,int> pii;
const int N=505,inf=1e9;
int n,trans[N][N];
pii a[N],b[N];
namespace KM{
int lx[N],ly[N],slk[N],mth[N],prt[N],pre[N];
bool vs[N];
inline int delta(int a,int b){return lx[a]+ly[b]-trans[a][b];}
inline bool bfs(int p){
mth[0]=p;
for(ri i=1;i<=n;++i)vs[i]=0,pre[i]=0,slk[i]=0x3f3f3f3f;
int x,y=0,dt,nxt;
do{
vs[y]=1,x=mth[y],dt=inf;
for(ri t,i=1;i<=n;++i){
if(!vs[i]){
t=delta(x,i);
if(t<slk[i])slk[i]=t,pre[i]=y;
if(slk[i]<dt)dt=slk[i],nxt=i;
}
}
for(ri i=0;i<=n;++i){
if(vs[i])lx[mth[i]]-=dt,ly[i]+=dt;
else slk[i]-=dt;
}
y=nxt;
}while(mth[y]);
while(y)mth[y]=mth[pre[y]],y=pre[y];
}
inline void solve(){
for(ri i=1;i<=n;++i)bfs(i);
for(ri i=1;i<=n;++i)prt[mth[i]]=i;
for(ri i=1;i<=n;++i)cout<<prt[i]<<' ';
}
}
int main(){
#ifdef ldxcaicai
freopen("lx.in","r",stdin);
#endif
n=read();
for(ri i=1;i<=n;++i)a[i].fi=read(),a[i].se=read();
for(ri i=1;i<=n;++i)b[i].fi=read(),b[i].se=read();
for(ri i=1;i<=n;++i)for(ri j=1;j<=n;++j)trans[i][j]=a[i].fi*b[j].fi+a[i].se*b[j].se;
puts("Yes");
KM::solve();
return 0;
}