• [考试反思]0909csp-s模拟测试41:反典


    说在前面:我是反面典型!!!不要学我!!!

    说在前面:向rank1某脸学习,不管是什么题都在考试反思后面稍微写一下题解。

    这次是真的真的运气好。。。

    这次知识点上还可以,但是答题策略出了问题。。。

    幸亏平时攒的rp生效了(前一天比较耐心的教不少人题来着,与某脸形成对比rp++)(然而可能也并不耐心)

    考试过程:

    考前,大脸说他可能不是第一个AK csp-s赛制的人,但是应该是第一个AC的。

    于是我的目标就变成了抢第一个AC:我要快速切掉最简单的题!!!

    考前flag必倒。。。

    于是反正第一步就是先找到最简单的题吧。。。

    过了一边三道题:T1显然需要找规律并不是很快能切掉,T2数据结构去死吧不会

    等等,T3这是啥?大力模拟?STL set可以水?

    发现自己hack不掉,然后就开始码。

    好写好调。(其实都没怎么调,过编译就过样例)

    刚好这题没有大一点的样例,我就直接交了。

    然而心急了。细节打错了!

    不要给自己凭空施压!

    从时间上看的确是第一个,但不是第一个AC。。。

    考后5分钟乱改就A了。

    然后相较于T2当然我宁愿滚去推式子于是T2暴力都没有打。

    然后就去推式子了。然后就差不多死了。(详见下方题解)

    暴力很好弄啊。。。但是用了一个小时

    但是我的暴力始终过不了小样例里的某一个询问,其实是我手抄样例时抄错了。

    我还以为我打错了,心态略崩。抱着骗分的想法继续了。

    然后发现会MLE,优化,又用了一个小时。。。

    这还是比某孩子tdcp直接MLE0好一些的。

    不要忘了还有MLE这种错。

    于是我还有20分钟,不抛弃不放弃去T2打暴力。

    14分钟完成,过不了样例结果发现和我手模结果一致。。。我手模都不对。。。?!

    又看错题了!!!

    做题之前不管时间多么紧迫一定要好好看题再手模一个样例!!!不要白费时间!!!

    然后就结束了,平时一定会炸一道题,我就交了两个如果炸掉一个的话就只剩100分/80分了

    但是rp爆发没有爆炸,拿到了100+空白+80=180。

    然后教练说:吴迪是一个反面示范。

    我错了了了了了了了。。。。。

    一定要打暴力!!!!

    题解区:

    T1:夜莺与玫瑰

    我的式子是$ sumlimits_{i=1}^{n-1} sumlimits_{j=1}^{m-1} [gcd(i,j)==1] imes (min(i,n-i) imes (m-j) + min(j,m-j) imes (n-i) - min(i,n-i) imes min(j,m-j)) $

    很长,很丑,但是有具体含义,我给Alpaca解释过了但是实在太复杂,对实际含义感兴趣的可以来找我。

    现在的问题是化简。

    我们可以发现最不好搞的两项就是min的项,但是只要分类讨论i和n-i的关系以及j同理,那么就可求了。

    当i和j分别小于n/2和m/2时,式子的值可以化简为$ sumlimits_{i=1}^{n/2} sumlimits_{j=1}^{m/2} [gcd(i,j)==1] n*j+m*i-i*j*3 $

    在其他情况下,同理可以化简为只含有ij,im,jn,ij的项

    那么我们可以预处理ij,i,j,1在gcd(i,j)==1时的前缀和,4个二维数组干上再O(1)计算即可

    发现会MLE。

    那么我们就可以离线所有询问,使询问的n递增,我们一次只处理二位数组的一行就行了。

     1 //for(int i=1;i<=n-1;++i)for(int j=1;j<=m-1;++j)if(gcd(i,j)==1)
     2 //    ans+=min(n-i,i)*(m-j)+(n-i)*min(m-j,j)-min(n-i,i)*min(m-j,j);
     3 #include<cstdio>
     4 #include<algorithm>
     5 using namespace std;
     6 const long long mod=1<<30;
     7 long long sig_1[4005],sig_i[4005],sig_j[4005],sig_ij[4005];
     8 long long si_1[4005],si_i[4005],si_j[4005],si_ij[4005];
     9 long long s_1,s_i,s_j,s_ij;
    10 int gcd(int a,int b){return b?gcd(b,a%b):a;}
    11 struct ps{int m,n,ord,ans;}p[10005];
    12 bool com_n(ps a,ps b){return a.n<b.n;}
    13 bool com_ord(ps a,ps b){return a.ord<b.ord;}
    14 void Mod(long long &p){if(p>=mod)p-=mod;}
    15 int main(){
    16     int T,p1=0,p2=0;
    17     scanf("%d",&T);
    18     for(int i=1;i<=T;++i)scanf("%d%d",&p[i].n,&p[i].m),p[i].ord=i;
    19     sort(p+1,p+1+T,com_n);
    20     for(int i=1;i<=T;++i){
    21         int n=p[i].n,m=p[i].m;
    22         while(p1<n/2){
    23             p1++;
    24             for(int j=1;j<=2000;++j){
    25                 if(gcd(p1,j)==1)s_1++,Mod(s_i+=p1),Mod(s_j+=j),(s_ij+=p1*j)%=mod;
    26                 Mod(sig_1[j]+=s_1),Mod(sig_i[j]+=s_i),
    27                 Mod(sig_j[j]+=s_j),Mod(sig_ij[j]+=s_ij);
    28             }
    29             s_1=s_i=s_j=s_ij=0;
    30         }
    31         while(p2<n-1){
    32             p2++;
    33             for(int j=1;j<=4000;++j){
    34                 if(gcd(p2,j)==1)s_1++,Mod(s_i+=p2),Mod(s_j+=j),(s_ij+=p2*j)%=mod;//if(j<=2)printf("--%lld
    ",s_1);
    35                 Mod(si_1[j]+=s_1),Mod(si_i[j]+=s_i),
    36                 Mod(si_j[j]+=s_j),Mod(si_ij[j]+=s_ij);//if(j<=2)printf("%lld
    ",si_1[j]);
    37             }
    38             s_1=s_i=s_j=s_ij=0;
    39         }
    40         p[i].ans=(mod+(
    41             (-n*m*sig_1[m/2]-4*sig_ij[m/2]+2*sig_i[m/2]*m+2*sig_j[m/2]*n)
    42             +
    43             (n*m*si_1[m-1]+si_ij[m-1]-si_i[m-1]*m-si_j[m-1]*n)
    44         )%mod)%mod;//printf("%lld %lld %lld %lld
    ",si_1[m-1],si_ij[m-1],si_i[m-1],si_j[m-1]);
    45     }
    46     sort(p+1,p+1+T,com_ord);
    47     for(int i=1;i<=T;++i)printf("%lld
    ",(p[i].ans*2+p[i].n+p[i].m)%mod);
    48 }
    View Code

    记录思想(包括其它大神用的):

    • 离线
    • 记忆化gcd(去掉log)
    • 反演(带根号回答询问)
    • 拆式子,去min,max,保留不同的0,1,2次项求前缀和
    • 卡空间,运行内存实际很小,2×4000×4000在128M下可过
    • 询问排序递增,单调指针硬扫

    T2:影子

    考场上没打,不多说

    前置知识:树的直径。

    树上任意一点开始dfs,距离最远的点一定是直径的两个端点之一。

    接下来按照点权排序,从大到小解锁每一个点。

    然后我们用并查集维护当前树的直径以及端点,每次合并AB时分别讨论:

    1.直径就是A里的直径

    2.就是B里的

    3-6.是从A的端点里选一个,走到目前枚举的边,再走到B的一个端点

    取最优决策,用直径×点权更新ans。

    因为前两种情况里直径一定被更大或相等的点权枚举过,所以用较小的点不会使ans变大,故决策最优。

    预处理,倍增求LCA,树上前缀和,实现O(log)查询两点距离。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 using namespace std;
     5 #define int long long
     6 int t,n,fir[100005],l[200005],to[200005],cnt,f[100005],al[100005],p1[100005],p2[100005];
     7 int ans,v[200005],d[100005],F[20][100005],dep[100005],dt[100005];
     8 struct ps{int p,v;friend bool operator<(ps a,ps b){return a.v>b.v;}}p[100005];
     9 void link(int a,int b,int vv){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;v[cnt]=vv;}
    10 int find(int k){return f[k]==k?k:f[k]=find(f[k]);}
    11 void dfs(int p,int fa){
    12     F[0][p]=fa;dep[p]=dep[fa]+1;
    13     for(int i=1;i<=19;++i)F[i][p]=F[i-1][F[i-1][p]];
    14     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dt[to[i]]=dt[p]+v[i],dfs(to[i],p);
    15 }
    16 int DT(int a,int b){//printf("DT:%lld %lld
    ",a,b);
    17     int A=a,B=b,subdep=dep[a]-dep[b];
    18     if(subdep<0)subdep=-subdep,a^=b^=a^=b,A^=B^=A^=B;
    19     for(int i=0;i<=19;++i)if(subdep&1<<i)a=F[i][a];
    20     if(a==b)return dt[A]-dt[B];
    21     for(int i=19;~i;--i)if(F[i][a]!=F[i][b])a=F[i][a],b=F[i][b];
    22     a=F[0][a];
    23     return dt[A]+dt[B]-dt[a]-dt[a];
    24 }
    25 main(){//freopen("b.in","r",stdin);
    26     //freopen("x.in","r",stdin);//freopen("my.out","w",stdout);
    27     scanf("%lld",&t);
    28     while(t--){
    29         scanf("%lld",&n);
    30         for(int i=1;i<=n;++i)f[i]=p1[i]=p2[i]=i;
    31         for(int i=1;i<=n;++i)scanf("%lld",&p[i].v),p[i].p=i;
    32         sort(p+1,p+1+n);
    33         for(int i=1,a,b,vv;i<n;++i)scanf("%lld%lld%lld",&a,&b,&vv),link(a,b,vv),link(b,a,vv);
    34         dfs(1,0);
    35         for(int i=1;i<=n;++i){
    36             int P=p[i].p;al[P]=1;//printf("Unlocked : %lld
    ",P);
    37             for(int j=fir[P];j;j=l[j])if(al[to[j]]){
    38                 int F=find(to[j]);f[F]=P;
    39                 int d1=DT(P,p1[P]),d2=DT(P,p2[P]),totd,c1,c2;
    40                 if(d1>d2)totd=d1,c1=p1[P];else totd=d2,c1=p2[P];//printf("%lld %lld %lld %lld
    ",d1,d2,p1[P],p2[P]);
    41                 d1=DT(to[j],p1[F]),d2=DT(to[j],p2[F]);
    42                 if(d1>d2)totd+=d1,c2=p1[F];else totd+=d2,c2=p2[F];//printf("%lld %lld %lld %lld
    ",d1,d2,p1[F],p2[F]);
    43                 if(totd+v[j]>d[P])d[P]=totd+v[j],p1[P]=c1,p2[P]=c2;//,puts("UPD");
    44                 if(d[F]>d[P])d[P]=d[F],p1[P]=p1[F],p2[P]=p2[F];
    45                 ans=max(ans,d[P]*p[i].v);//printf("%lld %lld %lld %lld
    ",to[j],d[P],p1[P],p2[P]);
    46             }
    47         }printf("%lld
    ",ans);
    48         for(int i=1;i<=n;++i)fir[i]=d[i]=al[i]=0;
    49         cnt=ans=0;
    50     }
    51 }
    View Code

    思路积累:

    • 并查集维护联通块
    • 树的直径性质
    • 点分治做法(没打,但是简单粗暴,难打好想)
    • 贪心,按顺序解锁点
    • 预处理做到O(log)求树上点对距离{树上差分+倍增LCA}
    • 要会打暴力

    T3:玫瑰花精

    set大力模拟即可。

    维护两个set,一个存两个花精之间的间隔,另一个存位置。

    不断按照题意insert,erase即可。

     1 #include<cstdio>
     2 #include<set>
     3 #include<vector>
     4 using namespace std;
     5 struct ps{
     6     int dt,sp;
     7     friend bool operator<(ps a,ps b){
     8         return a.dt/2>b.dt/2||(a.dt/2==b.dt/2&&a.sp<b.sp);
     9     }
    10 };
    11 set<ps>bl;set<int>p;
    12 int n,m,o,x,ip[1000005];
    13 int main(){//freopen("c.in","r",stdin);
    14     scanf("%d%d",&n,&m);
    15     while(m--){
    16         scanf("%d%d",&o,&x);
    17         if(o==1){
    18             if(p.size()==0)p.insert(0),ip[x]=0,puts("1");
    19             else if(p.size()==1){
    20                 int xx=*p.begin();
    21                 if(xx>=n>>1)p.insert(0),ip[x]=0,puts("1"),bl.insert((ps){xx,0});
    22                 else p.insert(n-1),ip[x]=n-1,printf("%d
    ",n),bl.insert((ps){n-xx-1,xx});
    23             }
    24             else{
    25                 int p1=*p.begin(),p2=n-(*(--p.end()))-1,p3=(*bl.begin()).dt/2,p3p=(*bl.begin()).sp;
    26                 if(p1>=p2&&p1>=p3)p.insert(0),ip[x]=0,puts("1"),bl.insert((ps){p1,0});
    27                 else if(p2>p3)p.insert(n-1),ip[x]=n-1,printf("%d
    ",n),bl.insert((ps){p2,n-p2-1});
    28                 else{
    29                     int l=p3p,r=(*bl.begin()).dt+p3p,xx=l+r>>1;
    30                     p.insert(xx);ip[x]=xx;printf("%d
    ",xx+1);
    31                     bl.insert((ps){r-xx,xx});bl.insert((ps){xx-l,l});
    32                     bl.erase(bl.begin());//printf("%d %d %d
    ",l,r,xx);
    33                 }
    34             }
    35         }else{
    36             if(p.size()<=2)p.erase(ip[x]),bl.clear();
    37             else{
    38                 if(ip[x]==(*p.begin()))bl.erase((ps){(*p.upper_bound(ip[x]))-ip[x],ip[x]});
    39                 else if(ip[x]>=(*(--p.end())))bl.erase((ps){ip[x]-(*(--p.end())),(*(--p.end()))});
    40                 else{
    41                     int lp=*(--(p.lower_bound(ip[x]))),rp=*(p.upper_bound(ip[x]));
    42                     bl.erase((ps){rp-ip[x],ip[x]});bl.erase((ps){ip[x]-lp,lp});
    43                     bl.insert((ps){rp-lp,lp});
    44                 }
    45                 p.erase(ip[x]);
    46             }
    47         }
    48     }
    49 }
    View Code

    思路积累:

    • STL的熟练应用
    • 线段树维护最长区间(同《旅馆Hotel》,我还没有A)
    • 代码实现细节,注意先后顺序
    • 重载比较函数的多样性
  • 相关阅读:
    [转]VSTO Office二次开发RibbonX代码结构
    [转]VSTO+WinForm+WebService+WCF+WPF示例
    Ext Js简单Data Store创建及使用
    Web页面常用文件格式文件流的输出
    VSTO Office二次开发PPTRibbonX命令操作及对象添加
    VSTO Office二次开发键盘鼠标钩子使用整理
    VSTO Office二次开发对PPT自定义任务窗格测试
    VSTO Office二次开发对PowerPoint功能简单测试
    Ext Js简单Tree创建及其异步加载
    VB获取和更改文件属性
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11498807.html
Copyright © 2020-2023  润新知