CSP-S模拟测试69 题解

一如既往的垃圾,又回到了那个场场垫底的自己,明明考场上都想到正解了,但是就是拿不到分,可能是互奶把rp用光了吧以后一定加强训练代码能力。

T1:

考场上一直yy矩阵快速幂,虽然自己矩阵快速幂一点都不会还是硬着头皮yy,发现不可做之后并没有及时转化思路,但其实自己预处理的数组就是正解。

切记:不仅矩阵快速幂是log的,普通快速幂也是2333

然后这题其实很水啊,我们设$dp[i][j]$为前$i$列放$j$个棋子的方案数,然后枚举最后一列放多少个棋子就好了。

转移方程为$dp[i][j]=\sum{dp[i-1][j-k]*C_n^k}$,这样转移m列显然不行,考虑性质,第$i$列和第$i+kn$列的摆放方式一定相同,所以后面的组合数乘还有多少这样的列就好了即${C_n^k}^{\frac{m-i}{n}+1}$,但这样的复杂度是$O(n^4logn)$的,发现组合数可以预处理,于是去掉了log

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e5+10,mod=1e9+7;
 4 #define int long long
 5 int n,m,c,fac[N],inv[N];
 6 int f[105][105*105],pre[105][105*105];
 7 int min(int a,int b){
 8     return a<b?a:b;
 9 }
10 int qpow(int a,int b){
11     int ans=1;
12     while(b){
13         if(b&1) ans=ans*a%mod;
14         b>>=1;
15         a=a*a%mod;
16     }
17     return ans%mod;
18 }
19 int C(int a,int b){
20     return fac[a]*inv[b]%mod*inv[a-b]%mod;
21 }
22 signed main(){
23     fac[0]=1;
24     for(int i=1;i<=10001;++i) fac[i]=fac[i-1]*i%mod;
25     inv[10001]=qpow(fac[10001],mod-2);
26     for(int i=10001;i;--i) inv[i-1]=inv[i]*i%mod;
27     scanf("%lld%lld%lld",&n,&m,&c);
28     f[0][0]=1;
29     for(int i=0;i<=n;++i) for(int j=0;j<=max(n,c);++j) pre[i][j]=qpow(C(n,j),(m-i)/n+1)%mod;
30 //    for(int i=1;i<=n;++i,cout<<endl) for(int j=1;j<=n;++j) cout<<pre[i][j];
31     for(int i=1;i<=n;++i){
32         for(int j=0;j<=c;++j){
33             for(int k=0;k<=min(n,j);++k){
34                 (f[i][j]+=f[i-1][j-k]*pre[i][k]%mod)%=mod;
35 //                cout<<pre[i][k]<<" "<<qpow(C(n,k),(m-i)/n+1)<<endl;
36             }
37         }
38     }
39     printf("%lld",f[n][c]%mod);
40 }
41 /*
42 2 3 1
43 */
chess

T2:

考场上先想到单调栈,但是后来成功理解错题意对拍5w组WA0 2333。

如果理解对题意的话单调栈就挺明显了吧,肯定要找它前面第一各比他大的,那么答案一定在这段区间中,有一个比较明显的贪心就是,最优决策点一定是在,高度最小的那个点,稍想一下就可以明白。

所以在弹栈的时候每次更新,高度最小的下标即可。

对于输入量大的题,快读真的很有必要。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e7+10;
 4 pair<int,int > s[N];
 5 int a[N],sta[N],top;
 6 inline int min(int a,int b){return a<b?a:b;}
 7 inline int max(int a,int b){return a>b?a:b;} 
 8 inline int read(){
 9     register int p=0;register char ch=getchar();
10     while(ch<'0'||ch>'9') ch=getchar();
11     while(ch>='0'&&ch<='9') p=(p<<3)+(p<<1)+ch-48,ch=getchar();
12     return p;
13 }
14 
15 int main(){
16     int n;
17     scanf("%d",&n);++n;
18     for(register int i=1;i^n;++i) a[i]=read();
19 //    for(int i=1;i<=n;++i) s[i].first=a[i],s[i].second=i;
20     sta[++top]=0;a[0]=0x7fffffff;
21     register int ans=1;
22     for(register int i=1;i^n;++i){
23         s[i]=make_pair(a[i],i);
24         while(a[i]>=a[sta[top]]){
25             s[i]=min(s[i],s[sta[top--]]);
26             
27         }ans=max(ans,i-s[i].second+1);
28         sta[++top]=i;
29     }
30     printf("%d",ans);
31 }
array

T3:

回滚莫队裸题。

就维护两个数组now1,now2,分别代表x向左向右能伸展的最长连续值域。

分别用x+1,x-1更新。还有就是更新一下这整段区间的左右端点以保证以后更新答案正确,中间的不用更新因为不会在插入了。

当这个区间左端点和上一个区间左端点不一样时,直接清空你now1,now2数组。

做完了之后觉的理解更加深入了。

放个回滚莫队讲解链接

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+10;
 4 int blo[N];
 5 int sta1[N],sta2[N],top;
 6 struct node{
 7     int l,r,id,ld;
 8     bool friend operator < (node a,node b){
 9         return blo[a.l]==blo[b.l]?(a.r<b.r):blo[a.l]<blo[b.l];
10     }
11 }ask[N];
12 int now1[N],now2[N],a[N],ans[N];
13 int main(){
14 //freopen("ants1.in","r",stdin);
15 //freopen("my.out","w",stdout);
16     int n,m;
17     scanf("%d%d",&n,&m);
18     int size=sqrt(n);
19     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
20     for(int i=1;i<=m;++i){
21         scanf("%d%d",&ask[i].l,&ask[i].r);
22         ask[i].id=i;
23         ask[i].ld=(ask[i].l-1)/size+1;
24     }
25     for(int i=1;i<=n/size+1;++i){
26         for(int j=size*(i-1)+1;j<=size*i;++j) blo[j]=i;
27     }
28     sort(ask+1,ask+m+1);
29     int r=0,l=1,res=0;
30     for(int i=1;i<=m;++i){
31         if(ask[i].ld!=ask[i-1].ld){
32             for(int j=0;j<=n;++j) now1[j]=now2[j]=0;
33             res=0;
34             l=r=ask[i].ld*size;
35         }
36         while(ask[i].r>r){
37             ++r;
38             int x=a[r];
39             now1[x]=now1[x+1]+1;
40             now2[x]=now2[x-1]+1;
41             int kh=now1[x]+now2[x]-1;
42             now1[x-now2[x]+1]=kh;
43             now2[x+now1[x]-1]=kh;
44             res=max(kh,res);
45         }
46         top=0;
47         int tmp=res;
48         for(int j=ask[i].l;j<=min(ask[i].r,l);++j){
49             int x=a[j];
50             now1[x]=now1[x+1]+1;
51             now2[x]=now2[x-1]+1;
52             int kh=now1[x]+now2[x]-1;
53             sta1[++top]=x-now2[x]+1;
54             sta2[top]=now1[x-now2[x]+1];
55             sta1[++top]=x+now1[x]-1;
56             sta2[top]=now2[x+now1[x]-1];
57             now1[x-now2[x]+1]=kh;
58             now2[x+now1[x]-1]=kh;
59             tmp=max(kh,tmp);
60         }
61         for(int j=top;j;--j){
62             if(j&1) now1[sta1[j]]=sta2[j];
63             else now2[sta1[j]]=sta2[j];
64         }
65         for(int j=ask[i].l;j<=min(l,ask[i].r);++j){
66             now1[a[j]]=0;
67             now2[a[j]]=0;
68         }
69         ans[ask[i].id]=tmp;
70     }
71     for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
72 }
ants

 

posted @ 2019-10-12 12:15  Barça_10  阅读(243)  评论(1编辑  收藏  举报