• [考试反思]0921csp-s模拟测试49:困顿


    太弱。还是太弱。

    拉不开分差,离第一机房分数线估计还是300多分。

    但是,还是要骂:XX出题人。

    部分分非常少且没有意义,T1基本只有0/纯暴力20/100三个档,

    T2正解是n2但是n3一分不给,还要卡n2的空间,T3的n5有51分但没有任何提示,除了送了与正解根本就无关的7分。

    而且造的数据还出了锅,这个出题人啊。。。

    出题人是有多痛恨人类。

    开考看题。

    T1上来先看错了题以为是xor,然后就是trie裸题了,然后直接开始打。

    很快地打出来发现过不了样例,然后发现是mod。

    重新看题,全不会,傻眼了。

    想再找一道最简单的题先做稳住,但是无从下手。

    刚开始T2有一个n3的思路,发现没有设分,就绝望了。

    想了一个半小时多吧,想出了n2,然后发现卡空间。

    太弱了没有直接想到正解,zkt就知道直接按x排序,我和脸和toot都是按y排的。

    然后大脸秒掉了空间优化,toot放弃了空间优化拿80分走了。

    我以为只有50分于是不想放弃,但是剩下两题还没有打,于是走了。

    回去弄了一个T1的随机化+测试点分治暴力,然后忘记取模,本来40分的代码炸成0了。

    因为没有打正解所以就没有打对拍。。。

    然后T3顺手把特殊性质7分拿下,直接放弃。

    回T2,对拍,然后空间优化。

    思路还可以,可以节约25%的空间,但是忘了vector会翻倍导致空间浪费,于是结果就是和toot没优化一样,80分。

    暴力也要打对拍。

    对于卡空间的题要精打细算,注意vector的2倍空间。

    get黑科技:resize。

    还是没有能把所有能拿下的分拿下,还是弱啊。。。

    T1:养花

    分块。预处理块中对于100001的所有询问的最大答案。

    预处理的方法类似于lower_bound但是可以记在数组上就去掉了不必要的log。

    开数组lst[i]记录下这个块里小于等于i的值里的最大值。

    那么对于每一个询问就可以搞了:mod k的最大值就是max(lst[k-1],lst[2k-1]-k,lst[3k-1]-2k...)

    而计算这个式子的复杂度是调和级数$sumlimits_{i=1}^{n} frac{n}{i} = ln n$

    所以总的复杂度就是$O(sqrt{n} imes 100001 imes ln 100001 + m sqrt{n})$

    然而其实不是$sqrt{n}$,会T的,块要开的稍大一点(1300左右)跑的能快一些

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 #define S 1234
     5 #define N 100001
     6 int lst[100005],n,m,x[130005],Ans[101][130005],bl[130005];
     7 int main(){
     8     scanf("%d%d",&n,&m);
     9     const int bs=(n-1)/S+1;
    10     for(int i=1;i<=n;++i)scanf("%d",&x[i]);
    11     for(int i=1;i<=bs;++i){
    12         for(int j=1;j<=N;++j)lst[j]=0;
    13         for(int j=(i-1)*S+1;j<=i*S&&j<=n;++j)lst[x[j]]=x[j],bl[j]=i;
    14         for(int j=1;j<=N;++j)lst[j]=max(lst[j-1],lst[j]);
    15         for(int j=2;j<=N;++j)for(int k=j;;k+=j){
    16             if(k>N){Ans[i][j]=max(Ans[i][j],lst[N]%j);break;}
    17             Ans[i][j]=max(Ans[i][j],lst[k-1]%j);
    18         }
    19     }
    20     for(int t=1,l,r,q;t<=m;++t){
    21         scanf("%d%d%d",&l,&r,&q);int ans=0;
    22         if(bl[l]==bl[r])for(int i=l;i<=r;++i)ans=max(ans,x[i]%q);
    23         else{
    24             for(int i=l;i<=bl[l]*S;++i)ans=max(ans,x[i]%q);
    25             for(int i=(bl[r]-1)*S+1;i<=r;++i)ans=max(ans,x[i]%q);
    26             for(int i=bl[l]+1;i<bl[r];++i)ans=max(ans,Ans[i][q]);
    27         }printf("%d
    ",ans);
    28     }
    29 }
    View Code

    思路积累:

    • 分块不一定都是暴力。
    • 预处理所有询问。

    T2:折射

    dp式子都不一样。我说我的按y排序后的n2空间的了。(因为另一种我并想不到)

    先把x离散化,然后按y排序。我是dp[i][j]表示选到了第i个装置,上上个选的装置的x是j。

    先考虑n3,emm还是不说了吧真的是暴力啊,加个if就行。

    然后其实我们发现是一个区间加,那么前缀和一下复杂度就对了。

    这时候的dp[i][x[j]]+=dp[j][x[i]];

    我们发现对于每一个i只从前面的i-1项转移而来,那么总的就是1/2 n2而不是n2

    那么我们把要加的项目提前放进vector里,把dp数组滚动,就不会再炸空间了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<vector>
     4 using namespace std;
     5 vector<int>num[6001];
     6 vector<short>pos[6001];
     7 int mod(int p){return p>=1000000007?p-1000000007:p;}
     8 struct ps{int x,y;friend bool operator<(ps a,ps b){return a.y>b.y;}}p[6005];
     9 bool com(ps a,ps b){return a.x<b.x;}
    10 int dp[6001],n,ans;
    11 int main(){
    12     scanf("%d",&n);
    13     for(int i=1;i<=n;++i)scanf("%d%d",&p[i].x,&p[i].y);
    14     sort(p+1,p+1+n,com);
    15     for(int i=1;i<=n;++i)p[i].x=i;
    16     sort(p+1,p+1+n);
    17     for(int i=1;i<=n;++i) num[i].resize(i-1),pos[i].resize(i-1);
    18     for(int i=1;i<=n;++i){
    19         for(int j=1;j<=n;++j)dp[j]=0;
    20         for(int j=0;j<num[i].size();++j)dp[pos[i][j]]=mod(dp[pos[i][j]]+num[i][j]);
    21         num[i].clear();pos[i].clear();
    22         for(int j=1;j<i;++j)dp[p[j].x]++;
    23         for(int j=1;j<p[i].x;++j)dp[j]=mod(dp[j]+dp[j-1]);
    24         for(int j=n;j>p[i].x;--j)dp[j]=mod(dp[j]+dp[j+1]);
    25         ans=mod(ans+mod(dp[p[i].x-1]+dp[p[i].x+1]));
    26         for(int j=i+1;j<=n;++j)num[j][j-i-1]=dp[p[j].x],pos[j][j-i-1]=p[i].x;
    27     }
    28     printf("%d
    ",mod(ans+n));
    29 }
    View Code

    思路积累:

    • resize
    • 前缀和

    T3:画作

    大神题。

    有一个结论就是最优方案中一定有一种的所有操作的交集不是空集。

    那么我们只要抓住某一个点向四周扩展,把所有同色区域取反就好了,知道全部区域都是白色。

    复杂度$O(n^5)$

    同色区域被多次扩展了,我们只在乎最远的点几次能扩展几次。

    同色连0边,异色连1边,跑bfs即可。

    因为懒得打双端队列所以开了100个队列。。。(因为曼哈顿距离不会超过100)

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 const int xx[]={1,0,0,-1},yy[]={0,1,-1,0};
     5 #define tx X+xx[p]
     6 #define ty Y+yy[p]
     7 char s[55][55];int o[55][55],n,m,dt[55][55],qx[105][2555],qy[105][2555],qh[105],qt[105],ans=123;
     8 int main(){
     9     scanf("%d%d",&n,&m);
    10     for(int i=1;i<=n;++i)scanf("%s",s[i]+1);
    11     for(int x=1;x<=n;++x)for(int y=1;y<=m;++y)dt[x][y]=1000;
    12     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)o[i][j]=s[i][j]-'0';
    13     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
    14         dt[i][j]=0;qh[0]=qt[0]=1;qx[0][1]=i;qy[0][1]=j;
    15         for(int k=1;k<=100;++k)qh[k]=1,qt[k]=0;
    16         for(int k=0;k<=100;++k)for(int l=qh[k];l<=qt[k];++l){
    17             int X=qx[k][l],Y=qy[k][l];
    18             for(int p=0;p<=3;++p)if(dt[tx][ty]>dt[X][Y]+(o[X][Y]^o[tx][ty]))
    19                 dt[tx][ty]=dt[X][Y]+(o[X][Y]^o[tx][ty]),
    20                 qx[dt[tx][ty]][++qt[dt[tx][ty]]]=tx,
    21                 qy[dt[tx][ty]][qt[dt[tx][ty]]]=ty;
    22         }
    23         int mx=0;
    24         for(int x=1;x<=n;++x)for(int y=1;y<=m;++y)mx=max(mx,dt[x][y]),dt[x][y]=1000;
    25         mx+=mx&1^o[i][j];
    26         ans=min(ans,mx);
    27     }printf("%d
    ",ans);
    28 }
    View Code
  • 相关阅读:
    区块链分布式云存储项目盘点
    区块链一定要知道的的七大认识误区
    以太坊“空块”数量激增有什么影响?
    区块链技术涉及哪些编程语言?
    一文读懂实用拜占庭容错(PBFT)算法
    清除浮动的影响
    滚动条
    分享侧栏例子
    最最最简单的轮播图(JQuery)
    3D动画
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11566052.html
Copyright © 2020-2023  润新知