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,我们可以直接得知左子树的根节点,然后由左子树大小得知右子树根节点,然后确定每个根节点的左子树的大小范围,然后转移就好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }