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 */
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 }
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 }