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

原文地址:https://www.cnblogs.com/leom10/p/11660786.html

时间: 2024-10-09 06:23:56

CSP-S模拟测试69 题解的相关文章

[CSP-S模拟测试59]题解

以后题解还是单独放吧. A.Divisors 根号筛求所有数的因子,扫一遍去重统计即可. #include<cstdio> #include<iostream> #include<cstring> #include<vector> #include<map> using namespace std; const int N=205; int a[N],m,n; map<int,int> bu; vector<int> re

CSP-S 模拟测试57题解

人生第一次A,B层一块考rank2,虽然说分差没几分,但还是值得纪念. 题解: T1 天空龙: 大神题,因为我从不写快读也没有写考场注释的习惯,所以不会做,全hzoi就kx会做,kx真大神级人物. T2 巨神兵: 大神题,一看数据范围这么小,我们考虑状压,最傻逼的暴力思路是压边,但是这显然不行.正解是压点,设$f[s]$为当前选定点集状态为$s$的方案数. 我们考虑转移,当前选定的点集肯定是可以通过边和没有连过来的点相连构成新的方案.所以转移所以我们考虑枚举补集的子集$k$,设$cnt$为s与k

[CSP-S模拟测试96]题解

以后不能再借没改完题的理由不写题解了…… A.求和 求$\sum \sum i+j-1$ 柿子就不化了吧……这年头pj都不考这么弱智的公式化简了…… 坑点1:模数不定,可能没有2的逆元,那么只要先把乘数里的2去掉就好了. 坑点2:1e18炸long long $\rightarrow$ 慢速乘即可 #include<cstdio> #include<iostream> #include<cstring> #include<vector> using name

[CSP-S模拟测试97]题解

A.小盆友的游戏 感觉题解解释的很牵强啊……还是打表找规律比较靠谱 对于每个人,它构造了一个期望函数$f(x)$,设它的跟班个数为$cnt[x]$,那么令$f(x)=2^{cnt[x]}-1$(??鬼知道为什么要等于这个) 然后再定义当前局面的期望函数为每个人期望函数之和. 然后你会发现每次猜拳后局面期望函数变化量都是1 那么期望步数其实就是终止局面期望函数值-初始局面期望函数值 $ans=2^{n-1}-1-\sum (2^{cnt[x]}-1)$ #include<bits/stdc++.h

[CSP-S模拟测试53]题解

A.u 只涉及到区间修改可以考虑差分,然而如果每一行都差分复杂度还是过高.我们发现差分标记也是连续的(一行横着的一行斜着的),所以可以维护两个 差分的差分,扫两遍统计即可. #include<cstdio> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=2005; int read() { int x=0,f=1;char ch=ge

[CSP-S模拟测试60]题解

回去要补一下命运石之门了…… A.嘟嘟噜 给定报数次数的约瑟夫,递推式为$ans=(ans+m)\% i$. 考虑优化,中间很多次$+m$后是不用取模的,这种情况就可以把加法变乘法了.问题在于如何找到下一次需要取模的位置. 解不等式$ans+km \ge i+k$即可,需要处理一下边界. 据说可以证明复杂度是$O(m \log n)$的,但我不是很会. //考场代码 稍丑 #include<bits/stdc++.h> using namespace std; typedef long lon

[CSP-S模拟测试63]题解

A.Median 这题的数据生成方式并没有什么规律,所以可以认为是随机数据. 维护一个桶,表示当前K长区间里的值域情况. 并且用变量记录中位数值域上的左侧有多少个数,当区间调整时一并调整桶和这个变量即可. 由于是随机数据,所以每次的调整幅度并不会很大,近似于常数. 复杂度$O(n)$. #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespa

[考试反思]1011csp-s模拟测试69:无常

承蒙大脸skyh的毒奶,加之以被kx和Parisb以及板儿逼剥夺了一中午的睡眠(其实还有半个晚上)RP守恒终于失效了,连续两场没考好 RP也是不够了,竟然考原题,而且还不换题,连样例都一模一样只不过加强了数据范围 关键是当时没有几个人学了回滚莫队,学长也没讲我就没学... 后悔...但的确就是不会,能有什么办法呢? 话说回滚莫队真的是联赛知识点吗?那我真的是太菜了... T1比较简单.至少我比较擅长.因为实在是困所以弄了半天没用的东西,用了40分钟才A(居然是首杀???) 然后继续懵逼,困的不行

csp-s模拟测试69

A. chess 看到范围一开始猜是矩阵快速幂,开始推按列转移的dp,正方形之间有交集不好转移. 换了个角度,都恰好有c个,那么我在滑动正方形的时候损失几个就要获得几个,然后就看出了列之间的相等关系. 推了个$\Theta(n^4logm)$的dp.码完测了下n=50都T飞,怀疑人生10min,发现k没限制n打成了$\Theta(n^5logm)$ 改完发现100依然T飞,然后慌了(因为懊悔T3是原题但我没学回滚莫队...),忘记当时为什么以为log提不出来了orz. 打完dp,观察复杂度瓶颈,