T1【JSOI2011】分特产
题目分析
很容易想到求补集,即有人没有特产的方案数。
我们枚举有至少多少个人没有土特产。
那么补集的答案就是至少1个人没有土特产的方案数-至少2个人没有土特产的方案数+至少3个人没有土特产的方案数-...。
那么至少(i)个人没有土特产的方案数怎么求呢?
对于每一种土特产,我们要分给剩余(n-i)个人,方案数即为(C^{n-i-1}_ {m+n-i-1})。
因此预处理出组合数,枚举(i)统计即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod=1000000007;
int n,m,a[2005],c[2005][2005];
void init(){
c[0][0]=1;
for(int i=1;i<=2000;i++){
c[i][0]=1;
for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
int main(){
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)scanf("%d",&a[i]);
int ans=0;
for(int i=0;i<=n;i++){
int sum=1,tot=n-i,f=(i&1)?1:-1;
for(int j=1;j<=m;j++)sum=1ll*sum*c[a[j]+tot-1][tot-1]%mod;
ans=(ans+1ll*-f*c[n][i]%mod*sum)%mod;
}
cout<<(ans+mod)%mod<<"
";
}
T2 【PA2014】Final Zarowki
题目分析
挖坑代填
T3 【JLOI2015】城池攻占
题目分析
一眼倍增啊。观察数据范围,发现乘的都是正数。那么显然无论怎么乘、加减,最终战斗力都能写成(a* x+b(a>0))这样的式子。那么对于这个一次函数显然(x)是单调递增的。因此我们可以对于树上每一个点(i)倍增求出从(i)向上占领(2^j)步,所需的最小战斗力(lim[i][j])。同时预处理出(Mul[i][j],Plus[i][j])表示从(i)向上占领(2^j)步后战斗力(x)应变为(Mul[i][j]* x+Plus[i][j])。
#include <bits/stdc++.h>
using namespace std;
inline char Getchar(){
static char buffer[1<<20],*S,*T=S;
return T==S?T=(S=buffer)+fread(buffer,1,1<<20,stdin),*S++:*S++;
}
template<class T>
inline void read(T &x){
x=0;T f=1;char ch=getchar();
while(!isdigit(ch))ch!='-'?:f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
x*=f;
}
typedef long long ll;
const int Maxn=300005;
int n,m,h[Maxn],p[Maxn][20],dep[Maxn],cnt[Maxn],ans[Maxn];
ll Mul[Maxn][20],Plus[Maxn][20];
long double lim[Maxn][20];
struct node{
ll a,v,h;
}a[Maxn];
int main(){
// freopen("attack.in","r",stdin);
// freopen("attack.out","w",stdout);
read(n);read(m);
for(int i=1;i<=n;i++)read(a[i].h);
for(int i=0;i<=18;i++)Mul[0][i]=Mul[1][i]=1;
for(int i=1;i<=n;i++){
if(i!=1)read(p[i][0]),read(a[i].a),read(a[i].v);
dep[i]=dep[p[i][0]]+1;
if(a[i].a)Plus[i][0]=0,Mul[i][0]=a[i].v;
else Plus[i][0]=a[i].v,Mul[i][0]=1;
lim[i][0]=a[i].h;
for(int j=1;j<=18;j++){
p[i][j]=p[p[i][j-1]][j-1];
Plus[i][j]=Plus[i][j-1]*Mul[p[i][j-1]][j-1]+Plus[p[i][j-1]][j-1];
Mul[i][j]=Mul[i][j-1]*Mul[p[i][j-1]][j-1];
lim[i][j]=max(lim[i][j-1],(lim[p[i][j-1]][j-1]-Plus[i][j-1])/Mul[i][j-1]);
}
}
for(int i=1;i<=m;i++){
ll s;int c;
read(s);read(c);
int t=c;
for(int j=18;~j;j--)if(lim[t][j]<=s){
s=s*Mul[t][j]+Plus[t][j];t=p[t][j];
}
cnt[t]++;ans[i]=dep[c]-dep[t];
}
for(int i=1;i<=n;i++)cout<<cnt[i]<<"
";
for(int i=1;i<=m;i++)cout<<ans[i]<<"
";
}
/*
x*a+b>=lim
x*a>=lim-b
x>=(lim-b)/a
*/