CSPS模拟86-87
Posted loadingkkk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSPS模拟86-87相关的知识,希望对你有一定的参考价值。
模拟86
T1,烧水,按位统计贡献,利用某种sao操作避免数位dp
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 const int mod=1000000007; 6 using namespace std; 7 int n,m; 8 int dp1[40],sum[40]; 9 int bin[40]; 10 inline void get1(int x) 11 { 12 memset(dp1,0,sizeof(dp1)); 13 if(x<0)return; 14 for(int i=29;~i;--i) 15 { 16 dp1[i]=(x>>(i+1))+1; 17 if(x&bin[i])dp1[i]=1ll*bin[i]*dp1[i]%mod; 18 else{ 19 dp1[i]=1ll*(x>>(i+1))*bin[i]%mod; 20 dp1[i]+=(x&(bin[i]-1));++dp1[i]; 21 if(dp1[i]>=mod)dp1[i]-=mod; 22 } 23 } 24 } 25 int main() 26 { 27 for(int i=0;i<=30;++i)bin[i]=1<<i; 28 int T;scanf("%d",&T); 29 while(T--) 30 { 31 scanf("%d%d",&m,&n); 32 memset(sum,0,sizeof(sum)); 33 get1(n); 34 for(int i=0;i<=30;++i)sum[i]+=dp1[i]; 35 get1(m-1); 36 for(int i=0;i<=30;++i)sum[i]-=dp1[i]; 37 int ans=0;const int num=n-m+1; 38 for(int i=0;i<=30;++i) 39 { 40 ans+=2ll*sum[i]%mod*(num-sum[i])%mod*bin[i]%mod; 41 if(ans>=mod)ans-=mod; 42 } 43 ans=((ans%mod)+mod)%mod; 44 cout<<ans<<endl; 45 46 } 47 }
T2,博弈,考场上推出了最小为0时的答案,以为能找出规律,连暴力都没打,kuku
正解为用必败状态筛必胜状态来保证复杂度。%%%脸哥压表,处理出不合法状态hash掉,最后在数组里lower_bound即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define re register 6 using namespace std; 7 int n,m; 8 int a[5]; 9 char dp[301][301][301]; 10 int main() 11 { 12 for(re short i=0;i<=300;++i) 13 { 14 for(re short j=0;j<=300;++j) 15 { 16 for(re short k=0;k<=300;++k) 17 { 18 if(dp[i][j][k])continue; 19 for(re short o=1;o+i<=300;++o)dp[i+o][j][k]=1; 20 for(re short o=1;o+j<=300;++o)dp[i][j+o][k]=1; 21 for(re short o=1;o+k<=300;++o)dp[i][j][k+o]=1; 22 for(re short o=1;o+i<=300&&o+j<=300;++o)dp[i+o][j+o][k]=1; 23 for(re short o=1;o+i<=300&&o+k<=300;++o)dp[i+o][j][k+o]=1; 24 for(re short o=1;o+k<=300&&o+j<=300;++o)dp[i][j+o][k+o]=1; 25 for(re short o=1;o+i<=300&&o+k<=300&&o+j<=300;++o)dp[i+o][j+o][k+o]=1; 26 } 27 } 28 } 29 int T;scanf("%d",&T); 30 while(T--) 31 { 32 scanf("%d%d%d",&a[1],&a[2],&a[3]); 33 if(dp[a[1]][a[2]][a[3]])puts("Yes"); 34 else puts("No"); 35 } 36 }
T3,dp,对前缀和取max优化。考场上想出了第三维表示四个状态(顶峰,底端,上升,下降),然而没想到转移。
在最外层枚举区间数,对四种状态用4个变量分别维护最优点转移即可。%%%WWB_star,rnb,milk_feng让我认识到自己的错误
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define N 30040 6 using namespace std; 7 int n,K,ans; 8 int a[N],sum[N],dp[205][N][5]; 9 const int inf=0x3f3f3f3f; 10 int main() 11 { 12 memset(dp,-0x3f,sizeof(dp)); 13 scanf("%d%d",&n,&K); 14 for(int i=1;i<=n;++i) 15 scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i]; 16 int mi=0,ma=0,mi2=0,ma2=0; 17 for(int i=1;i<=n;++i){ 18 dp[1][i][2]=sum[i]-mi; 19 dp[1][i][1]=ma-sum[i]; 20 dp[1][i][0]=dp[1][i][2]; 21 dp[1][i][3]=dp[1][i][1]; 22 mi=min(mi,sum[i]);ma=max(ma,sum[i]); 23 } 24 for(int j=2;j<K;++j){ 25 mi=ma=mi2=ma2=-inf; 26 for(int i=j-1;i<=n;++i) 27 { 28 dp[j][i][2]=max(dp[j][i][2],ma+2*sum[i]); 29 dp[j][i][1]=max(dp[j][i][1],mi-2*sum[i]); 30 31 dp[j][i][0]=max(dp[j][i][0],mi2); 32 dp[j][i][3]=max(dp[j][i][3],ma2); 33 mi=max(mi,dp[j-1][i][2]+sum[i]*2); 34 mi=max(mi,dp[j-1][i][0]+sum[i]*2); 35 36 ma=max(ma,dp[j-1][i][1]-sum[i]*2); 37 ma=max(ma,dp[j-1][i][3]-sum[i]*2); 38 39 ma2=max(ma2,dp[j-1][i][1]); 40 ma2=max(ma2,dp[j-1][i][3]); 41 42 mi2=max(mi2,dp[j-1][i][2]); 43 mi2=max(mi2,dp[j-1][i][0]); 44 } 45 } 46 mi=ma=mi2=ma2=-inf; 47 for(int i=K-1;i<=n;++i) 48 { 49 dp[K][i][2]=max(dp[K][i][2],ma+sum[i]); 50 dp[K][i][1]=max(dp[K][i][1],mi-sum[i]); 51 52 dp[K][i][0]=max(dp[K][i][0],mi2); 53 dp[K][i][3]=max(dp[K][i][3],ma2); 54 55 mi=max(mi,dp[K-1][i][2]+sum[i]); 56 mi=max(mi,dp[K-1][i][0]+sum[i]); 57 58 ma=max(ma,dp[K-1][i][1]-sum[i]); 59 ma=max(ma,dp[K-1][i][3]-sum[i]); 60 61 ma2=max(ma2,dp[K-1][i][1]); 62 ma2=max(ma2,dp[K-1][i][3]); 63 64 mi2=max(mi2,dp[K-1][i][2]); 65 mi2=max(mi2,dp[K-1][i][0]); 66 67 ans=max(ans,dp[K][i][2]); 68 ans=max(ans,dp[K][i][1]); 69 } 70 printf("%d ",ans); 71 }
300 | 145 | 120 | 50 | 110 | 220 | 122 | 160 | 130 |
这个故事告诉我们:rp是个好东西(别败光了)
模拟87,新的开始,勉强苟住位置(抢到Dybala的第八)
T1,(妹子)maze
考场上想了半天才想到是二分答案。然后就疯狂码码码,打了个代码测时长,发现极限数据甚至会达到十几秒,然后疯狂卡常
最后当我手打堆打到一半,发现我的结构体重载运算符重载反了,赶紧改过来,发现还剩1分钟,慌的一比。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<bitset> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #define N 105 10 using namespace std; 11 const double eps=1e-5; 12 const int dx[]={1,-1,0,0}; 13 const int dy[]={0,0,1,-1}; 14 int n,m,sx,sy,tx,ty; 15 bool vst[N][N]; 16 double dis[N][N],s; 17 int a[N][N]; 18 struct node{ 19 int x; 20 int y; 21 double z; 22 friend bool operator <(const node &a,const node &b) 23 {return a.z>b.z;} 24 }; 25 /* 26 struct QAQ{ 27 node a[100500]; 28 int tot; 29 inline int size(){return tot;} 30 inline void clear(){tot=0;} 31 inline node top(){return a[1];} 32 inline void pop() 33 { 34 a[1]=a[tot++];int i=1,j; 35 while(1) 36 { 37 j=i<<1; 38 if(j>tot)return; 39 if(a[j+1]<a[j]) 40 } 41 } 42 43 } 44 */ 45 priority_queue<node>q; 46 inline void init() 47 { 48 for(register int i=1;i<=n;++i) 49 for(register int j=1;j<=m;++j) 50 dis[i][j]=1000000.0; 51 } 52 inline node mknd(int x,int y,double z) 53 { 54 node a;a.x=x,a.y=y,a.z=z;return a; 55 } 56 inline void dijk(double val) 57 { 58 while(q.size())q.pop();init(); 59 dis[sx][sy]=0.0; 60 q.push(mknd(sx,sy,0.0)); 61 int xx,yy,x,y;double z; 62 while(q.size()) 63 { 64 x=q.top().x;y=q.top().y;z=q.top().z;q.pop(); 65 if(z!=dis[x][y])continue;if(x==tx&&y==ty)return; 66 for(register int i=3;~i;--i) 67 { 68 xx=x+dx[i];yy=y+dy[i]; 69 if(a[xx][yy])continue; 70 if(dx[i]) 71 { 72 if(dis[xx][yy]>z+val) 73 { 74 dis[xx][yy]=z+val; 75 q.push(mknd(xx,yy,dis[xx][yy])); 76 } 77 } 78 else 79 { 80 if(dis[xx][yy]>z+1.0) 81 { 82 dis[xx][yy]=z+1.0; 83 q.push(mknd(xx,yy,dis[xx][yy])); 84 } 85 } 86 } 87 } 88 } 89 inline void work() 90 { 91 double l=0.0,r=s,mid; 92 while(r-l>3e-4){ 93 mid=(l+r)*0.5;dijk(mid); 94 if(dis[tx][ty]-s>0.0)r=mid; 95 else l=mid; 96 if(fabs(dis[tx][ty]-s)<5e-4){l=mid;break;} 97 // printf("%.10lf %.10lf ",l,r); 98 } 99 printf("%.3lf ",l); 100 } 101 int main() 102 { 103 // freopen("da.in","r",stdin);//freopen("my.out","w",stdout); 104 scanf("%d%d%d%d%d%d",&n,&m,&sx,&sy,&tx,&ty); 105 for(int i=1;i<=n;++i) 106 for(int j=1,x;j<=m;++j) 107 scanf("%d",&x),a[i][j]=x; 108 109 a[sx][sy]=a[tx][ty]=0; 110 dijk(1.0);if(dis[tx][ty]>100000.0)return 0; 111 for(int i=1;i<=n;++i)a[i][0]=a[i][m+1]=1; 112 for(int i=1;i<=m;++i)a[0][i]=a[n+1][i]=1; 113 scanf("%lf",&s);work();return 0; 114 } 115 /* 116 4 4 117 1 1 4 4 118 0 0 1 1 119 1 0 0 0 120 0 0 1 0 121 0 0 0 0 122 5 123 */
T2,bird
线段树稍显然,考虑去除重复贡献,用到了一些差分的思想,在左端点加入区间,右点存左点,dp值单点插入时暂且不加当前贡献,扫到右端点再加,保证不重复
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<bitset> 6 #include<vector> 7 #include<queue> 8 #define N 500050 9 using namespace std; 10 int n,m; 11 vector<int>v[N]; 12 int sum[N],dp[N]; 13 struct node{ 14 int l,r; 15 }q[100050]; 16 int A,ans; 17 int ma[N<<2],tag[N<<2]; 18 inline void upd(int g){ma[g]=max(ma[g<<1],ma[g<<1|1]);} 19 inline void down(int g) 20 { 21 tag[g<<1]+=tag[g]; 22 ma[g<<1]+=tag[g]; 23 tag[g<<1|1]+=tag[g]; 24 ma[g<<1|1]+=tag[g]; 25 tag[g]=0; 26 } 27 inline void add(int g,int l,int r,int x,int y,int v) 28 { 29 if(l>y||r<x)return; 30 if(l>=x&&r<=y){ma[g]+=v;tag[g]+=v;return;} 31 if(tag[g])down(g); 32 const int m=l+r>>1; 33 add(g<<1,l,m,x,y,v);add(g<<1|1,m+1,r,x,y,v); 34 upd(g); 35 } 36 inline int ask(int g,int l,int r,int x,int y) 37 { 38 if(l>y||r<x)return 0; 39 if(l>=x&&r<=y)return ma[g]; 40 if(tag[g])down(g); 41 const int m=l+r>>1; 42 const int a1=ask(g<<1,l,m,x,y),a2=ask(g<<1|1,m+1,r,x,y); 43 if(a1>a2)return a1;return a2; 44 } 45 int main() 46 { 47 scanf("%d%d",&n,&m); 48 for(int i=1,l,r;i<=n;++i) 49 { 50 scanf("%d%d",&l,&r); 51 if(r<0)continue; 52 if(l<0)l=0; 53 v[r+1].push_back(l); 54 if(r>A)A=r; 55 ++sum[l]; 56 } 57 ++A;int al=0; 58 for(int i=0;i<=A;++i) 59 { 60 al+=sum[i]; 61 for(int j=0;j<v[i].size();++j) 62 add(1,0,A,v[i][j],i-1,1),--al; 63 dp[i]=ask(1,0,A,0,i-m); 64 ans=max(ans,dp[i]+al); 65 add(1,0,A,i,i,dp[i]); 66 } 67 cout<<ans<<endl; 68 return 0; 69 }
T3,%%%脸哥
话说脸哥是不是把推荐和反对放反了啊?
以上是关于CSPS模拟86-87的主要内容,如果未能解决你的问题,请参考以下文章