**T1 shampagne
玩到一半我就不玩了真是菜成sb
玩一下链的情况,我们发现,只有在大小为222时BobBobBob必胜
对于大小为333的情况,显然AlanAlanAlan必胜
对于一个奇链,我们取左边第二个,这时BobBobBob只能取左边第一个,转化为更小的奇链
对于一个偶链,我们取左边第一个,这是BobBobBob只能取左边第二个,转化为一个更小的奇链
那么这个性质,我们可以推广到连通块上
其实感性认识就是每次删掉叶子节点还是叶子节点的父亲的区别?
具体证明如下




感觉很多博弈题都是这样…
从简单的情况推一个结论,然后推广到更复杂的情况上…
很多推广都感性认识一下??
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=5005;
struct edge{int x,y,next;}a[2*MAXN];int len,last[MAXN];
void ins(int x,int y){len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
int du[MAXN],n,K;
int pi[MAXN];
bool bk;
void dfs(int x,int fa)
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y!=fa)
{
dfs(y,x);
if(pi[y])continue;
if(pi[x])bk=false;
pi[x]=pi[y]=1;
}
}
}
int main()
{
freopen("shampagne.in","r",stdin);
freopen("shampagne.out","w",stdout);
n=read();K=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
ins(x,y);ins(y,x);
du[x]++;du[y]++;
}
bk=true;
dfs(1,0);
for(int i=1;i<=n;i++)bk&=(pi[i]!=0);
if(!bk||K<(n/2)-1)puts("Alan");
else puts("Bob");
return 0;
}
T2 whiskey
开始sb了以为是一个三维体积并
然后,我们可以枚举这个第一维xxx,把第二第三维y,zy,zy,z扔到平面上
那么只需要知道不合法的面积是什么
那么对于一个点,不合法的就是y≤yi,z≤ziy\leq y_i,z \leq z_iy≤yi,z≤zi的面积并
我们以yyy作为xxx轴,zzz作为yyy轴,那么一定是一个从左往右高度递减的图形
插入一个点的时候只需要找到前驱后继,讨论加入即可
对于后面的点,我们需要满足y>max(y),z>max(z)y> max(y),z>max(z)y>max(y),z>max(z),那么同理讨论一下就可以得到不合法面积了
线段树维护即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=500001;
int n,P,Q,R;
struct segtree
{
LL mn[MAXN*4],mx[MAXN*4],sum[MAXN*4],lazy[MAXN*4];
void down(int now,int l,int r)
{
if(!lazy[now])return ;
int mid=(l+r)/2;
mn[lc]=mx[lc]=lazy[now];mn[rc]=mx[rc]=lazy[now];
sum[lc]=1LL*(mid-l+1)*mn[lc];
sum[rc]=1LL*(r-mid)*mn[rc];
lazy[lc]=lazy[now];lazy[rc]=lazy[now];
lazy[now]=0;
}
int getpos(int now,int l,int r,int u)//找第一个小于他的位置
{
if(mn[now]>u)return -1;
if(l==r)return l;
int mid=(l+r)/2;down(now,l,r);
if(mn[lc]>=u)return getpos(rc,mid+1,r,u);
else return getpos(lc,l,mid,u);
}
int getpos1(int now,int l,int r,int u)
{
if(mx[now]<u)return -1;
if(l==r)return l;
int mid=(l+r)/2;down(now,l,r);
if(mx[rc]<=u)return getpos1(lc,l,mid,u);
else return getpos1(rc,mid+1,r,u);
}
void modify(int now,int l,int r,int ql,int qr,int u)
{
if(l==ql&&r==qr){mn[now]=mx[now]=lazy[now]=u;sum[now]=1LL*(r-l+1)*u;return ;}
int mid=(l+r)/2;down(now,l,r);
if(qr<=mid)modify(lc,l,mid,ql,qr,u);
else if(mid+1<=ql)modify(rc,mid+1,r,ql,qr,u);
else modify(lc,l,mid,ql,mid,u),modify(rc,mid+1,r,mid+1,qr,u);
mn[now]=min(mn[lc],mn[rc]);mx[now]=max(mx[lc],mx[rc]);
sum[now]=sum[lc]+sum[rc];
}
int getright(int now,int l,int r)
{
if(mn[now]!=0)return -1;
if(l==r)return l;
int mid=(l+r)/2;down(now,l,r);
if(mn[lc]==0)return getright(lc,l,mid);
else return getright(rc,mid+1,r);
}
LL getcal(int now,int l,int r,int ql,int qr)
{
if(l==ql&&r==qr)return sum[now];
int mid=(l+r)/2;down(now,l,r);
if(qr<=mid)return getcal(lc,l,mid,ql,qr);
else if(mid+1<=ql)return getcal(rc,mid+1,r,ql,qr);
else return getcal(lc,l,mid,ql,mid)+getcal(rc,mid+1,r,mid+1,qr);
}
}seg;
int mx1[21][MAXN],mx2[21][MAXN],Log[MAXN],bin[25];
struct node{int a,b,c;}w[MAXN];
bool cmp(node n1,node n2){return n1.a<n2.a;}
void init()
{
bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
for(int i=2;i<MAXN;i++)Log[i]=Log[i>>1]+1;
for(int i=1;i<=n;i++)mx1[0][i]=w[i].b,mx2[0][i]=w[i].c;
for(int i=1;bin[i]<=n;i++)
for(int x=1;x+bin[i]-1<=n;x++)
mx1[i][x]=max(mx1[i-1][x],mx1[i-1][x+bin[i-1]]),mx2[i][x]=max(mx2[i-1][x],mx2[i-1][x+bin[i-1]]);
}
int getmx(int l,int r,int o)
{
int K=Log[r-l+1];
if(o==1)return max(mx1[K][l],mx1[K][r-bin[K]+1]);
else return max(mx2[K][l],mx2[K][r-bin[K]+1]);
}
int sta[MAXN],tp;
int main()
{
freopen("whiskey.in","r",stdin);
freopen("whiskey.out","w",stdout);
n=read();P=read();Q=read();R=read();
for(int i=1;i<=n;i++)w[i].a=read(),w[i].b=read(),w[i].c=read();
sort(w+1,w+1+n,cmp);
init();
LL ans=0;
for(int i=1;i<=n;i++)
{
int sss=w[i].a-w[i-1].a;
LL su=seg.sum[1];
int u1=getmx(i,n,1),u2=getmx(i,n,2);
if(u1!=Q&&u2!=R)
{
LL ca=seg.getcal(1,1,Q,1,u1);
su=su-ca+1LL*u1*R;
int fir=seg.getpos(1,1,Q,u2);
if(fir!=-1)
{
int nw=max(u1+1,fir);
LL ca=seg.getcal(1,1,Q,nw,Q);
su=su-ca+1LL*(Q-nw+1)*u2;
}
}
else su=1LL*Q*R;
ans+=1LL*sss*(1LL*Q*R-su);
int fir=seg.getpos(1,1,Q,w[i].c);
if(i==1)seg.modify(1,1,Q,1,w[i].b,w[i].c);
else
{
if(fir==-1)//没有比我小的
{
int u=seg.getright(1,1,Q);
if(u==-1)continue;
if(u<=w[i].b)seg.modify(1,1,Q,u,w[i].b,w[i].c);
}
else
{
int lst=fir-1;
if(lst<1)seg.modify(1,1,Q,1,w[i].b,w[i].c);
else if(w[i].b>lst)seg.modify(1,1,Q,lst+1,w[i].b,w[i].c);
}
}
// printf("CHECKER\n");
//// pr2(ans);
// printf("ans=%lld\n",ans);
// for(int i=1;i<=Q;i++)pr1(seg.getcal(1,1,Q,i,i));
// puts("");
}
ans+=1LL*(1LL*Q*R-seg.sum[1])*(P-w[n].a);
pr2(ans);
}
**T3 vodka
好题
以为是OSUOSUOSU的加强版…然后想着怎么维护期望的次方与次方的期望的关系去了…
设一个xi,jx_{i,j}xi,j表示第iii个数在第jjj次是否被拿出来了
那么要求的就是
E((x1,1+x1,2+...+x1,n)F∗...∗(xL,1+xL,2+...+XL,n)F)E((x_{1,1}+x_{1,2}+...+x_{1,n})^F*...*(x_{L,1}+x_{L,2}+...+X_{L,n})^F)E((x1,1+x1,2+...+x1,n)F∗...∗(xL,1+xL,2+...+XL,n)F)
发现每一次选出任一个数的概率都是固定的,那么考虑用总数/方案数来算期望
把里面的式子拆一拆,那么可以得到内部用∗*∗连接的单项式,所以我们只需要求出下式期望的和
(x1,a[1,1]∗x1,a[1,2]∗...∗x1,a[1,F])∗...∗(xL,a[L,1]∗xL,a[L,2]∗...∗xL,a[L,F])(x_{1,a[1,1]}*x_{1,a[1,2]}*...*x_{1,a[1,F]})*...*(x_{L,a[L,1]}*x_{L,a[L,2]}*...*x_{L,a[L,F]})(x1,a[1,1]∗x1,a[1,2]∗...∗x1,a[1,F])∗...∗(xL,a[L,1]∗xL,a[L,2]∗...∗xL,a[L,F])
其中a[i,j]a[i,j]a[i,j]表示在第iii个括号中,取的第jjj个位置是哪个位置
即代表了我们要在第a[i][j]a[i][j]a[i][j]次取值时取出iii这个值
我们将其写成一个L∗FL*FL∗F的矩阵形式,显然的,任意两行不能有数相同。因为有数相同时一定有一个xxx为000,那么此时贡献就为000了。考虑其概率,假如矩阵中有TTT个相同的值,那么其概率为1KT\frac{1}{K^T}KT1,因为我们已经固定了KKK个位置是选择哪些数的
至此可以转化题意,在L∗FL*FL∗F的矩形中填入[1,n][1,n][1,n]的数,要求任意两行没有数相同,问填入的数的不同种类为TTT时的方案数
逐行dpdpdp,设f[i][j]f[i][j]f[i][j]为前iii个格子放了jjj种数,那么转移有f[i][j]=f[i−1][j−1]+f[i−1][j]∗jf[i][j]=f[i-1][j-1]+f[i-1][j]*jf[i][j]=f[i−1][j−1]+f[i−1][j]∗j
对于一行结果f[i][j]f[i][j]f[i][j],我们最后乘一个j!j!j!就可以得到总方案数,即整体更换任意种数的位置
那么再做LLL次背包dpdpdp,求出总共dp[i]dp[i]dp[i]表示放了iii种数的方案数,最后贡献即为
∑Cni∗i!∗1Ki∗dp[i]\sum C_n^i*i!*\frac{1}{K^i}*dp[i]∑Cni∗i!∗Ki1∗dp[i]
dpdpdp上界可能去到nnn?,我们发现模数是200320032003而前部分在i>=2003i>=2003i>=2003时已经为000了,所以只需要保存前mod−1mod-1mod−1个位置的值即可
上面的背包dpdpdp可以倍增优化,还可以加FFTFFTFFT进一步优化。使用倍增优化后复杂度即为O(mod2logL+mod2)O(mod^2logL+mod^2)O(mod2logL+mod2)
感觉,真的是一个很妙的题啊…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=2005;
const int mod=2003;
int pow_mod(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)ret=1LL*ret*a%mod;
a=1LL*a*a%mod;b>>=1;
}
return ret;
}
void ad(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int dp[MAXN][MAXN],inv[MAXN],n,K,L,F;
int C(int n,int m)
{
int ret=1;
for(int i=1;i<=m;i++)ret=1LL*ret*inv[i]%mod*(n-i+1)%mod;
return ret;
}
int f[MAXN];
int gets(int u)
{
int re=0;
while(u)re++,u>>=1;
return re;
}
int pre[MAXN],inve[MAXN];
int main()
{
freopen("vodka.in","r",stdin);
freopen("vodka.out","w",stdout);
pre[0]=1;
for(int i=1;i<MAXN;i++)pre[i]=pre[i-1]*i%mod;
inve[mod-1]=pow_mod(pre[mod-1],mod-2);
for(int i=mod-2;i>=0;i--)inve[i]=inve[i+1]*(i+1)%mod;
inv[0]=1;
for(int i=1;i<MAXN;i++)inv[i]=pow_mod(i,mod-2);
n=read();K=read();L=read();F=read();
dp[0][0]=1;
for(int i=1;i<MAXN;i++)
for(int j=1;j<=i;j++)dp[i][j]=(dp[i-1][j-1]+dp[i-1][j]*j)%mod;
f[0]=1;
int len=gets(L);
for(int i=len;i>=1;i--)
{
if(i!=len)
{
for(int j=mod;j>=0;j--)
{
int temp=0;
for(int k=0;k<j;k++)if(f[k])ad(temp,f[k]*f[j-k]%mod);
f[j]=temp;
}
}
if(L&(1<<(i-1)))
{
for(int j=mod;j>=0;j--)
{
int temp=0;
for(int k=0;k<j;k++)if(f[k])ad(temp,f[k]*dp[F][j-k]%mod);
f[j]=temp;
}
}
}
int ans=0;
for(int i=1;i<=min(n,mod);i++)
ad(ans,1LL*C(n,i)*pre[i]%mod*pow_mod(pow_mod(K,i),mod-2)%mod*f[i]%mod);
pr2(ans);
return 0;
}
1242

被折叠的 条评论
为什么被折叠?



