csp-s 模拟76

  这辈子第一个铜,虽然说不像别人不屑于记录这种rk3,但是我觉得我还是记录一下吧,鼓励一下子。

  这次考试吧,运气真的好,T1能想到正解,虽然旁边lsc大佬秒切T1,不过我还是凭借我强大的意志力稳定了心态,以至于T2可以好好的思考,最后T3一如既往的不会做,不过Catalan还是不难看出来的,水到了20分。

  有心态上的原因,有运气上的原因。这套题可能我做着比较顺手,可能是我较为擅长的类型,确实懵上了。但是说真的,实力并不是与之相称。

  说一说别的大佬吧。我很佩服wwb_star,他一直很稳,他的进步很大,但是很难看出来,但是慢慢的,他超越了很多人。这些东西说出来很难,只能意会,真的挺佩服他的。

  题目不是很难,思维量还可以,也挺合自己口味的。

T1 序列

  构造题,考场上数据分治全打了,然后对自己说了一百遍“就算我正解不会打,我最少也有70”,然后心态就渐渐的平和了,开始好好的想细节调代码。

  心态还是很重要的喵。

  题目不难,按照套路先打表,然后找规律。我们发现能构成合法序列的a+b不会大于n+1。这还不够,要找更细致的性质。

  对于a b,我们可以分开考虑,意思就是说我们把上升和下降分成两个部分,类似分块,把上升序列分成块,这些上升序列块组成下降序列块,大概就是:

6 7 8 9 4 5 2 3 1

  可以看出,我们可以把6 7 8 9、4 5、2 3、1分别看成块,便构造出来了一个 9 4 4 的块。

  这就很显然了,由这种构造方案可以得出成立条件$\left \lceil \frac{n-a}{b-1} \right \rceil <= a$,然后就搞就完事了。

  细节较多。

T2 购物

  结论题吧,挺好找的。

  显然物品跟顺序没啥关系,所以先排序(套路),然后我们发现,排完序后实际卡出来的区间跟我选哪个已经没关系了,当我选择前i个时,假设我一定要其中最大的元素,那么我卡出来的区间范围一定是$\left [ \left \lceil \frac{a_i}{2} \right \rceil,sum_i \right ]$,我们只需要判断一下i-1的最大值与i的最小值是否可以连在一起形成一个大区间就好了,不是很难。

T3 计数

  %%%skyh 30分钟秒掉。

  %%%xuefeng 小绿框。

  首先是考虑先序遍历的性质。(%%%%%rvalue学长)

  我多想把学长的题解整个粘下来。

  我们考虑u v,满足u的中序遍历小于v的中序遍历。

  • u<v 一 u是v的祖先,v是u的右子树。 二 u在lca的左子树,v在lca的右子树。
  • u>v v是u的祖先,u是v的左子树。

  然后就开始暴搜找先后关系,这些先后关系一定同时满足,所以是的关系。

  设$dp_{i,j}$表示在i为根,大小为j的子树下合法的个数。有了这个dp,我们可以将这种先后关系转化为枚举的左子树的大小。为什么是左子树?因为先序遍历性质4,我们可以直接得知左子树的根节点,然后由左子树大小得知右子树根节点,然后确定每个根节点的左子树的大小范围,然后转移就好了。

 1 #include<cstdio>
 2 #define LL long long
 3 #define HZOI std
 4 using namespace HZOI;
 5 const int mod=1e9+7;
 6 const int N=1003;
 7 int T,n,m;
 8 LL inv[N],F[N],Finv[N];
 9 LL dp[N][N],mn[N],mx[N];
10 LL Comb(int ,int );
11 void Init();
12 inline int read();
13 inline int min(int x,int y) {return x<y?x:y;}
14 inline int max(int x,int y) {return x>y?x:y;}
15 int main()
16 {
17 //    freopen("sample.in","r",stdin);
18     Init();
19     T=read();
20     while (T--)
21     {
22         n=read(),m=read();
23         for (int i=1; i<=n; ++i) mn[i]=0,mx[i]=n-i+1;
24         for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) dp[i][j]=0;
25         for (int i=1,x,y; i<=m; ++i)
26         {
27             x=read(),y=read();
28             if (x<y)
29             {
30                 for (int i=1; i<x; ++i) mn[i]=max(mn[i],i-x);
31                 mx[x]=min(y-x-1,mx[x]);
32             }
33             else mn[y]=max(mn[y],x-y);
34         }
35         for (int i=2; i<=n; ++i) dp[i][0]=1;
36         dp[n+1][0]=1;
37         for (int i=n; i; --i)
38         {
39             for (int j=mn[i]; j<=n-i+1; ++j)
40                 for (int k=mn[i]; k<=min(mx[i],j); ++k)
41                     dp[i][j]=(dp[i][j]+dp[i+1][k]*dp[i+k+1][j-k-1]%mod)%mod;
42         }
43         printf("%lld\n",dp[1][n]);
44     }
45 }
46 LL Comb(int x,int y)
47 {
48     return F[x]*1ll*Finv[y]%mod*Finv[x-y]%mod;
49 }
50 void Init()
51 {
52     inv[1]=1;
53     for (int i=2; i<=1000; ++i)
54         inv[i]=(mod-mod/i)%mod*1ll*inv[mod%i]%mod;
55     F[0]=Finv[0]=1;
56     for (int i=1; i<=1000; ++i)
57         F[i]=F[i-1]*1ll*i%mod,
58         Finv[i]=Finv[i-1]*1ll*inv[i]%mod;
59 }
60 inline int read()
61 {
62     int nn=0; char cc=getchar();
63     while (cc<'0' || cc>'9') cc=getchar();
64     while (cc>='0' && cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar();
65     return nn;
66 }
计数

猜你喜欢

转载自www.cnblogs.com/LH-Xuanluo/p/11689891.html