[考试反思]0927csp-s模拟测试53:沦陷

很喜欢Yu-shi说过的一句话

在OI里,菜即是原罪

对啊。

都会。谁信呢?

没有分数,你说话算什么呢?

你就是菜,你就是不对,没有别的道理。

最没有用的,莫过于改题大神,这就是菜的借口。

但是其实这次还是有很多长记性的地方。

T1厌氧死在O2上爆了100分。

自己测试和对拍时一定要记得打开O2。

T2正解但是记搜初值设0导致重复搜索丢61分。

记忆化搜索的初值要赋负数以防等于0的情况重复搜索。

 

T1:u

因为是区间加,很容易想到差分。

于是我们把矩阵的差分数组弄出来,发现每次操作只是把一条竖线或斜线上的一段加了一个值。

那么还是个区间加,再差分一次就好了。

开O2来调试,防止数组越界RE0分。

 1 #include<cstdio>
 2 #define int long long
 3 int n,q,cfl[5005][5005],cfx[5005][5005],ans;
 4 main(){//freopen("t1.in","r",stdin);freopen("t1.out","w",stdout);
 5     scanf("%lld%lld",&n,&q);
 6     for(int i=1,r,c,l,s;i<=q;++i){
 7         scanf("%lld%lld%lld%lld",&r,&c,&l,&s);
 8         cfl[r][c]+=s;cfx[r][c+1]-=s;
 9         if(r+l<=n)cfl[r+l][c]-=s;
10         if(r+l<=n&&c+l+1<=n)cfx[r+l][c+l+1]+=s;
11     }
12     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)cfl[i][j]+=cfl[i-1][j];
13     for(int i=1-n;i<n;++i)for(int j=i+1;j<=n;++j)if(j-i>=1&&j-i<=n&&j>=1&&j<=n)cfx[j][j-i]+=cfx[j-1][j-i-1];
14     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)cfl[i][j]+=cfx[i][j];
15     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)cfl[i][j]+=cfl[i][j-1],ans^=cfl[i][j];
16     printf("%lld\n",ans);
17 }
View Code

思路积累:

  • 二维差分

 

T2:v

第一个想法是状压。存每一位是否被移除。

但是我们发现这道题球只有两种颜色,我们如果用颜色的01串表示状态的话状态数只会变少不会变多。

结合记忆化搜索。因为存在大量权值接近于0的情况,所以记忆化搜索的初值最好设为负数来表现这里没有被搜过,不然会重复搜索导致实际效率低于普通状压。

我们所得到的01串并不能确切表示球序列,因为无法得知其长度(开头的那一段0是空还是黑球无法确定)

所以状态应有两个参数:长度与01串(30位,是个int型)

可以用pair压进map,也可以手写一个特别的hash表。

需要一些二进制操作来得到移除01串的某一位之后剩下的串(见代码?先右移再左移再把最后几位补上)

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 struct hash_map{
 5     int fir[50000020],l[30000005],to[30000005],cnt;short L[30000005],len;double v[30000005];
 6     double &operator[](int st){
 7         int r=st*1ll*len%50000017;
 8         for(int i=fir[r];i;i=l[i])if(to[i]==st&&L[i]==len)return v[i];
 9         l[++cnt]=fir[r];fir[r]=cnt;to[cnt]=st;L[cnt]=len;return v[cnt]=-1;
10     }
11 }m;
12 int n,k;char s[33];
13 double sch(int l,int st){
14     if(l==n-k)return 0.0;
15     m.len=l;if(m[st]>-0.5)return m[st];
16     m[st]=0;
17     int bls[33],rst=st;
18     for(int i=1;i<=l;++i)bls[i]=rst&1,rst>>=1;
19     for(int i=1;i<=l/2;++i){
20         int st1=st>>l-i+1<<l-i|st&(1<<l-i)-1,j=l-i+1,st2=st>>l-j+1<<l-j|st&(1<<l-j)-1;
21         double ans1=sch(l-1,st1)+bls[j],ans2=sch(l-1,st2)+bls[i];
22         m.len=l;m[st]+=2.0l/l*max(ans1,ans2);
23     }
24     if(l&1){
25         int p=l/2+1,st3=st>>l-p+1<<l-p|st&(1<<l-p)-1;
26         double ans=sch(l-1,st3)+bls[p];
27         m.len=l;m[st]+=1.0l/l*ans;
28     }
29     return m[st];
30 }
31 int main(){
32     scanf("%d%d%s",&n,&k,s);int sbcnt=0;
33     int st=0;for(int i=0;i<n;++i)st=st<<1|(s[i]=='W');
34     printf("%.8lf\n",sch(n,st));
35 }
View Code

思路积累:

  • 优秀的状态压缩
  • 哈希表:二维压pair类
  • 二进制运算
  • 记忆化搜索:初值赋-1

 

T3:w

原题改编。居然变成了一个dp???只会第一问不给部分分。。。

我打的极麻烦,和题解一样。两个dp数组分别表示此时最优决策。

最麻烦的地方在于处理目前这个点的度数是奇数还是偶数,然后怎么处理两个点之间是否连边。。。

开变量存当前是奇数时的最优决策r1,dt1,偶数时的最优决策r0,dt0

逐个加入每一个儿子更新这四个儿子。最后把所有儿子考虑完之后来得出与父亲连边和不连边时的最优决策。

大量的分类讨论,还有一些细节。

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n,fir[100005],l[200005],to[200005],v[200005],cnt,ans,num,dp1[2][100005],dp2[2][100005];
 5 void link(int a,int b,int V){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;v[cnt]=V;}
 6 void dfs(int p,int fa){
 7     int r0=0,r1=123456789,dt0=0,dt1=123456789;
 8     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
 9         dfs(to[i],p);int D10=dp1[0][to[i]],D11=dp1[1][to[i]],D20=dp2[0][to[i]],D21=dp2[1][to[i]];
10         if(!v[i])r0+=D10,r1+=D10,dt0+=D20,dt1+=D20;
11         else if(v[i]==1){
12             int _r0=r0,_r1=r1,_dt0=dt0,_dt1=dt1;
13             r1=_r0+D11;dt1=_dt0+D21;
14             r0=_r1+D11+1;dt0=_dt1+D21;
15         }else{
16             int _r0=r0,_r1=r1,_dt0=dt0,_dt1=dt1;
17             if(_r0+D11<_r1+D10||(_r0+D11==_r1+D10&&_dt0+D21<_dt1+D20))
18                 r1=_r0+D11,dt1=_dt0+D21;
19             else r1=_r1+D10,dt1=_dt1+D20;
20             if(_r0+D10<_r1+D11+1||(_r0+D10==_r1+D11+1&&_dt0+D20<_dt1+D21))
21                 r0=_r0+D10,dt0=_dt0+D20;
22             else r0=_r1+D11+1,dt0=_dt1+D21;
23         }
24     }
25     if(r0<r1+1||(r1+1==r0&&dt0<dt1))dp1[0][p]=r0,dp2[0][p]=dt0;
26     else dp1[0][p]=r1+1,dp2[0][p]=dt1;
27     if(r0<r1||(r0==r1&&dt0<dt1))dp1[1][p]=r0,dp2[1][p]=dt0+1;
28     else dp1[1][p]=r1,dp2[1][p]=dt1+1;
29 }
30 int main(){
31     scanf("%d",&n);
32     for(int i=1,a,b,c,d;i<n;++i)scanf("%d%d%d%d",&a,&b,&c,&d),link(a,b,c^d),link(b,a,c^d);
33     dfs(1,0);printf("%d %d\n",dp1[0][1],dp2[0][1]);
34 }
View Code

思路积累:

  • 大规模分类讨论
  • 树形dp
  • 奇数/偶数

 

 

 

把最没用的垃圾扔在最下面。无关人员请直接跳过。


 

也还好,这次没有出以前出过的锅。诚当涨记性。

太菜了。你真的太菜了。

会做而拿不到分,可悲可笑而不可怜,可恨可耻而不可悔。

翻身的希望依然渺茫。

你还是不够强,那又何必逞强呢?

你想去A层,这是人之常情,但是你还没有与之匹配的能力。

你只有不断的继续锻炼自己。

承认自己弱的确有心里落差。

但是只有这样才能稳住心态继续前进吧。


 

posted @ 2019-09-28 11:03  DeepinC  阅读(307)  评论(0编辑  收藏  举报