[考试反思]0428省选模拟82:胆量

为啥之前我说了一次:一有部分分我就活了。然后最近就基本又没啥部分分了啊。

又是经典的:不到一小时就交然后爆炸了系列。

$T1$大博弈论怎么办?

树没法打表。博弈不平等所以也不是很能$SG$

大胆猜测!猜了个结论然后手模发现它过了所有$n \le 6$的点,很开心。

然后就交了。结果还真的过且仅过了$n \le 6$的点。

$T2$是一个不算太难的线段树i想了一会也就写出来了。

$T3$是一个神奇的组合数学,想的方向不对且也没有跟上清奇思路。。

最后剩一个多小时有点绝望就去改昨天$T2$了。。。(这不以为能$220$吗。。。

没话说。。。就是脑子不够使胆还贼肥。然而这题又没法对拍我能怎么办啊。。。

(像大神一样直接秒正解就好了

 

T1:香槟

大意:树,博弈,先手每次可以占领一个未被占领的点,后手可以在任意时候切断若干边。后手每次可以选择一个未被占领的点然后占领所有与它距离$\le 1$的点(即使已被占领)。

问双方最优决策下后手能否占领所有点。切断边最多使用$k$次。$n \le 5 \times 10^3$

分类讨论。先不考虑切断边。

如果是一条链的话:

一个点,先手胜。

两个点,后手胜。

三个点,先手胜。

四个点也是先手胜。

更多点都是先手胜。

发现最优决策与奇数偶数有关。

如果长度是奇数,那么每次只要占领离端点距离为$1$的点,然后下一次后手就必须占领端点。每次链长缩短$2$。最后递归至$1$。

如果长度是偶数,那么每次只要占领端点,然后下一次后手就必须占领离端点距离为$1$的点。每次链长缩短$3$。递归为奇数情况。

如果是树发现是一样的你可以每次缩短$2$或$3$。如果不能那就说明是个离分叉点距离只有$1$的叶子。

这种情况你只要占领分叉点然后后手就必须占领这个叶子。然后就继续做了。

所以,先手会输,当且仅当整个图全都是长度为$2$的链。

也就是当且仅当 $k \ge \frac{n}{2}-1$且树存在完美匹配。$O(n)$

出题人这数据范围是跑了个$dinic$?

 1 #include<cstdio>
 2 #define S 10086
 3 int n,fir[S],l[S],to[S],ec,k;
 4 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
 5 int dfs(int p,int fa){
 6     int a=0;
 7     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)a+=dfs(to[i],p);
 8     return a>1?S:a^1;
 9 }
10 int main(){
11     scanf("%d%d",&n,&k);
12     for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),link(a,b),link(b,a);
13     puts(k<n/2-1||dfs(1,0)?"Alan":"Bob");
14 }
View Code

 

T2:威士忌

大意:每个人有三个属性$a_i,b_i,c_i$分别$\in [1,A][1,B][1,C]$。给出$n$个人,问有多少种属性使得你比任何一个人都至少有两个属性严格领先。$n,A,B,C \le 2 \times 10^5$

看起来像然而又不是三维偏序,但是还是尝试一下用类似套路解决。

我们把所有人按照$a$排序之后,枚举$a$。

然后发现所有人就都变成了两种限制,对于$a$大于等于当前枚举的$a$的人,要求你$b,c$都严格大于它。

否则要求你$b,c$至少有一个严格大于它。

然后以$b$为下标维护个数据结构。线段树和$set$都行。问题得到解决。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 #define S 2222222
 5 int n,A,B,C,mn[S],b[S],c[S],lz[S];long long v[S],ans;
 6 #define lc p<<1
 7 #define rc lc|1
 8 #define md (L+R>>1)
 9 struct P{int a,b,c;friend bool operator<(P x,P y){return x.a<y.a;}}p[S];
10 void down(int p,int L,int R){
11     lz[lc]=lz[rc]=mn[lc]=mn[rc]=lz[p];
12     v[lc]=lz[p]*(md-L+1ll); v[rc]=lz[p]*(R-md+0ll);
13     lz[p]=0;
14 }
15 long long ask(int l,int r,int p=1,int L=1,int R=B+1){
16     if(l<=L&&R<=r)return v[p];
17     if(lz[p])down(p,L,R);
18     return (l<=md?ask(l,r,lc,L,md):0)+(r>md?ask(l,r,rc,md+1,R):0);
19 }
20 int find(int x,int p=1,int L=1,int R=B+1){
21     if(L==R)return L;
22     if(lz[p])down(p,L,R);
23     return mn[lc]<=x?find(x,lc,L,md):find(x,rc,md+1,R);
24 }
25 void chg(int l,int r,int z,int p=1,int L=1,int R=B+1){
26     if(l<=L&&R<=r){lz[p]=mn[p]=z;v[p]=z*(R-L+1ll);return;}
27     if(lz[p])down(p,L,R);
28     if(l<=md)chg(l,r,z,lc,L,md); if(r>md)chg(l,r,z,rc,md+1,R);
29     mn[p]=mn[rc]; v[p]=v[lc]+v[rc];
30 }
31 int main(){
32     scanf("%d%d%d%d",&n,&A,&B,&C);
33     for(int i=1;i<=n;++i)scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
34     sort(p+1,p+1+n); p[n+1].a=A+1;
35     for(int i=n;i;--i)b[i]=max(b[i+1],p[i].b),c[i]=max(c[i+1],p[i].c);
36     int pt=1;
37     for(int a=1;a<=A;++a){
38         while(a>p[pt].a){
39             int x=find(p[pt].c);
40             if(x<=p[pt].b)chg(x,p[pt].b,p[pt].c);
41             pt++;
42         }int x=max(find(c[pt]),b[pt]+1);
43         ans+=(B-x+1ll)*(C-c[pt])+(x>b[pt]+1?(x-b[pt]-1ll)*C-ask(b[pt]+1,x-1):0);
44     }printf("%lld\n",ans);return 0;
45     for(int _a=1;_a<=A;++_a)for(int _b=1;_b<=B;++_b)for(int _c=1;_c<=C;++_c){
46         for(int i=1;i<=n;++i)if((_a>p[i].a)+(_b>p[i].b)+(_c>p[i].c)>=2);
47             else goto xxx;
48         ans--;xxx:;
49     }printf("%lld\n",ans);
50 }
View Code

 

T3:绝对伏特加

大意:$n$个变量$p_i\in[1,k]$等概率随机。$a_i$表示$i$出现次数。求$\prod\limits_{i=1}^{L} a_i^F$的期望。$mod = 2003,F \le 10^3,FL \le 5 \times 10^4,n,k \le 10^9$

先考虑$F=1$的情况。答案就相当于你枚举一个序列$A_{1...L}$,$A_i$表示$i$出现的位置。要求$A$序列不重复。

这样的话一个数多次出现会在枚举不同位置时被多次计数也就起到了乘法的作用。(乘法分配律)我们只需要计算序列数。

对于一个序列它出现的可能性是$\frac{1}{k^L}$。所以答案是$\frac{A_n^L}{k^L}$

如果$F>1$,那么对于同一种数内部做$F$次幂,就相当于在所有出现位置里可重复地选择$F$次。

也就是说我们要枚举一个二维序列$A[1..L][1..F]$表示第$[1,L]$个数它可重复的选定出现位置,第$[1,F]$次选定了哪里。

要求不同的数选定的位置集合不能有交集,而同一种数内部可以重复。

我们考虑枚举$A$这个二维序列里一共出现了多少种位置,并有序的分配给这$L$个数。

有序的解释是:首先分配给数字$1$与分配给数字$2$是不同的,再之在数字$1$的$A$序列中,$x,y$谁在前谁在后也是有区别的。

所以就是全排列而不是多重集排列。

考虑到分配,这里就已经是明显的是生成函数了,对于每一种数要把$F$次选定分配给$i$个数,且要求每个数都出现过。

这是第二类斯特林数。构造它的普通型生成函数然后做$L$次幂就是所有$L$个数都考虑到的结果。

答案就是$\sum \frac{A_n^i f^L(x)[x^i]}{k^i}$。

因为我们可以发现那个选排列一旦$i$超过$x$就是$x$的倍数。也就是说多项式只需要知道前$mod$项,更高的项会乘上$mod!$取模后就是$0$了。

所以暴力卷积就可以了。$O(mod^2log \ L)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 2003
 4 int n,k,f,l,s[S][S],b[S],a[S];long long r[S<<1],ans;
 5 int qp(int b,int t,int a=1){for(;t;t>>=1,b=b*b%S)if(t&1)a=a*b%S;return a;}
 6 void mul(int*x,int*y){
 7     for(int i=0;i<S;++i)for(int j=0;j<S;++j)r[i+j]+=x[i]*y[j];
 8     for(int i=0;i<S;++i)x[i]=r[i]%S,r[i]=0;
 9 }
10 int main(){
11     cin>>n>>k>>l>>f; s[0][0]=a[0]=1;
12     for(int i=1;i<=f;++i)for(int j=1;j<=i;++j)s[i][j]=(s[i-1][j-1]+s[i-1][j]*j)%S;
13     for(int i=0;i<=f;++i)b[i]=s[f][i];
14     for(int t=l;t;t>>=1,mul(b,b))if(t&1)mul(a,b);
15     for(int i=0,A=1;i<S;++i)ans+=A*1ll*a[i]*qp(qp(k%S,i),S-2),A=1ll*A*(n-i)%S;
16     cout<<ans%S<<endl;
17 }
View Code

 

posted @ 2020-04-28 18:01  DeepinC  阅读(256)  评论(0编辑  收藏  举报