标签:check ref play tin stdin putchar sig etc splay
现有\(n\)个砝码,重量分别为\(a_1,a_2,a_3,...,a_n\)。\(xzy\)太好吃了,于是吃掉了其中\(m\)个砝码。
现在\(xzy\)想知道,他在剩余的砝码中随机选取一些砝码(不能不选),正好称出\(k\)的重量的方案数?
但他要我们输出的是答案 除以 \(xzy\)吃掉砝码的方案数,并对\(6249433\)取模。
\(100pts\) \(n\leq20,m<n,a_i\leq100\)
显然可以设\(dp[i][sum]\)表示前\(i\)个数中随便取数后和为\(sum\)的方案数。
则枚举\(i\)和\(sum(sum\in[1,k])\),可得转移方程
\(dp[i][sum+a[i]]+=dp[i-1][sum]\)
\(dp[i][sum]+=dp[i-1][sum]\)
复杂度最坏为\(O(nk)\)
\(O(2^n)\)枚举去掉哪些砝码。
然后使用\(30pts\)算法即可。
使用快速幂和费马小定理(要求\(q\)为质数)
\[\frac{1}{p}=p^{mod-2}(\mod q)\]
就可以处理答案了。
复杂度\(O(2^nnk)\),理论会炸,但\(0.64s\)过了???
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll unsigned long long
#define re register
#define il inline
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=250,mod=6249433;
int n,m,k,a[N],dp[N][N*100],pr[N],vis[N];
ll ans;
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while((ch<‘0‘||ch>‘9‘)&&ch!=‘-‘) ch=getchar();
if(ch==‘-‘) t=-1,ch=getchar();
while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-48,ch=getchar();
return x*t;
}
il void wri(re ll x)
{
if(x<0) putchar(‘-‘),x=-x;
if(x>9) wri(x/10);
putchar(x%10+‘0‘);
}
il ll check(re ll x)
{
while(x>=mod) x-=mod;
return x;
}
il ll ksm(re ll x,re ll n)
{
re ll S=1,T=x;
while(n)
{
if(n&1) S=check(S*T);
T=check(T*T);
n>>=1;
}
return S;
}
il void solve()
{
//fp(i,1,n) printf("%d ",pr[i]);puts("");
fp(i,1,k) fp(j,0,n) dp[j][i]=0;
fp(i,1,n) dp[i][a[i]]=1;
fp(i,1,k)
fp(j,1,n)
if(!vis[j])
{
dp[j][i+a[j]]=check(dp[j][i+a[j]]+dp[pr[j]][i]);
dp[j][i]=check(dp[j][i]+dp[pr[j]][i]);
}
re int ysn=n;while(vis[ysn]&&ysn) --ysn;
ans=check(ans+dp[ysn][k]);
}
il void dfs(re int x,re int tot)
{
if(tot<0) return;
if(x==n+1) {if(!tot) solve();return;}
fp(i,0,1)
if(i) vis[x]=1,pr[x+1]=pr[x],dfs(x+1,tot-1),vis[x]=0,pr[x+1]=x;
else
{
if(a[x]>k) pr[x+1]=pr[x];
dfs(x+1,tot);
}
}
il ll jc(re ll s,re ll e,re int flag)
{
re ll pzy=1;
fp(i,s,e) pzy=check(pzy*i);
if(flag) pzy=ksm(pzy,mod-2);
return pzy;
}
int main()
{
freopen("htam.in","r",stdin);
freopen("htam.out","w",stdout);
re int T=gi();
while(T--)
{
n=gi()^ans,m=gi()^ans,k=gi()^ans;ans=0;
if(k==0) {puts("0");continue;}
fp(i,1,n) a[i]=gi(),pr[i]=i-1;
dfs(1,m);
re ll eat=1;
if(m) eat=check(jc(1,n-m,0)*jc(m+1,n,1));
//printf("%llu %llu\n",eat,ans);
ans=check(ans*eat);
wri(ans);putchar(‘\n‘);
}
fclose(stdin);
fclose(stdout);
return 0;
}
考场感想:
龟速模是卡常利器
标签:check ref play tin stdin putchar sig etc splay
原文地址:https://www.cnblogs.com/yanshannan/p/9192907.html