1217B - Zmei Gorynich
我还以为我思路错了,最后看数据的时候才发现原来是有一个细节弄错了,先让d从大到小排序,如果d[i]>h[i]那么可以看看只用这一种需要多少步,也可以看看用了这一种用到第j种可以秒杀的时候需要多少步(j<i),注意这个地方算步数的时候由于boss没死所以还是要加上d[i]的,就是这个地方出错了
const ll N=7e5+5;
const ll inf=1e18;
const ll mod=1e9+7;
ll t,n,x;
struct node{
ll d,h;
bool operator<(const node &a)const{
return d>a.d;
}
}a[110];
ll cal(ll i,ll y){
ll tmp=x-y;
if(a[i].d-a[i].h>=tmp) return 1;
ll u=tmp-a[i].h,v=a[i].d-a[i].h;
ll res=ceil(u*1.0/v);
return res;
}
int main(){
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&x);
ll ans=inf;
for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].d,&a[i].h);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
if(a[i].d<=a[i].h){
if(a[i].d>=x) ans=1;
}
else{
if(a[i].d>=x){ans=1;continue;}
ans=min(ans,cal(i,0));
for(int j=1;j<i;j++)
ans=min(ans,max(1LL,cal(i,a[j].d-a[i].h)+1LL));
}
}
printf("%lld\n", ans==inf?-1:ans);
}
system("pause");
return 0;
}
L - Perfect Matchings 树形dp,容斥原理
一个2n个结点的完全图,删去2n-1条边,这些边可以构成一棵树,求剩下的图可以有多少不同的集合可以满足这样的性质,有n条边,每两条边都不共享一个节点,也就是说每个节点都只连一条边。
假设没有删除这个操作的话可以把n个节点放到一边,然后去连另外的n个节点,也就是C(2n,n)*n!,
然后因为u-v和v-u是一样的,所以还要除以2^n,所以总的答案是编辑;但是它是有删除操作的,也就是生成树的那些边是不可以选的,所以要减去那些选了树上的边的方案数,假设dp[i][j][0/1]表示以i为根节点匹配了j条边i节点是否参与了匹配所能构成的方案数,那么如果在树上匹配了j条边,那么在树上的方案数就是x=(dp[1][j][0]+dp[1][j][1]),其余的n-j条边的方案数就是y=
编辑,
所以需要ans-=x*y,别的以此类推,可以看出这就是容斥,所以每一项还需要乘以(-1)^j,最后的ans就是答案了
第46届ICPC亚洲区域赛(沈阳)L-Perfect Matchings【dp,组合数学】 - QuantAsk - 博客园 (cnblogs.com)
2021 ICPC沈阳 L.Perfect Matchings(树形dp+容斥原理)_lwz_159的博客-CSDN博客
const int mod=998244353;
const double inf=1e18;
const double eps=1e-8;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
ll lcm(ll a,ll b){
return a*b/__gcd(a,b);
}
ll fac[50006],ifac[50006],invt[50006];
void init(){
fac[0]=ifac[0]=1;
invt[0]=1;invt[1]=getinv(2LL);
for(ll i=1;i<=5000;i++){
fac[i]=fac[i-1]*i%mod;
ifac[i]=getinv(fac[i]);
invt[i]=invt[i-1]*invt[1]%mod;
}
}
ll C(ll a,ll b){
return (fac[a]*ifac[a-b]%mod)*ifac[b]%mod;
}
ll head[2000006],cnt;
struct Edge{
ll from,to,next;
}edge[2000006];
void addedge(ll from,ll to){
edge[++cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt;
}
ll n,dp[4005][4005][2],siz[4005],g[4005][2];
void dfs(ll u,ll fa){
siz[u]=dp[u][0][0]=1;
for(int i=head[u];i;i=edge[i].next){
ll j=edge[i].to;
if(j==fa) continue;
dfs(j,u);
memset(g,0,sizeof(g));
for(int p=0;p<=siz[u]/2;p++)
for(int q=0;q<=siz[j]/2;q++){
g[p+q][0]=(g[p+q][0]+dp[u][p][0]*((dp[j][q][0]+dp[j][q][1])%mod)%mod)%mod;
g[p+q][1]=(g[p+q][1]+dp[u][p][1]*((dp[j][q][0]+dp[j][q][1])%mod)%mod)%mod;
g[p+q+1][1]=(g[p+q+1][1]+dp[u][p][0]*dp[j][q][0]%mod)%mod;
}
for(int p=0;p<=siz[u]/2+siz[j]/2+1;p++)
dp[u][p][0]=g[p][0],dp[u][p][1]=g[p][1];
siz[u]+=siz[j];
}
}
int main(){
init();
scanf("%lld",&n);
for(int i=1;i<=2*n-1;i++){
ll u,vv;
scanf("%lld%lld",&u,&vv);
addedge(u,vv);addedge(vv,u);
}
dfs(1,0);
ll ans=0;
for(int i=0;i<=n;i++){
ll x=(dp[1][i][0]+dp[1][i][1])%mod;
ll a=n-i;
ll y=(C(a*2,a)*fac[a]%mod)*invt[a]%mod;
if(i&1) ans=((ans-x*y%mod)+mod)%mod;
else ans=(ans+x*y%mod)%mod;
}
printf("%lld\n", ans);
system("pause");
return 0;
}