2.9_总结

—————————————- 牢骚 ————————————————-
今天的测验依旧爆炸垫底。难过归难过,究其原因是时间分配有问题。
大概是被雅礼的题虐惯了,看到第一题就想跳,今天全程没有看第一题我都不知道自己怎么想的,结果第一题实际上非常简单,成了全场唯一没有做的人。
花费了三个小时,想去得第二题的40分,最后一个小时匆匆写了一三题的暴力,结果第二题打的40分的表cena收不上去,mmp。
过后来看,觉得自己脑子真是不清楚…

我可能需要再考几次试才能摸清四个半小时应该怎么用,感觉现在还是一团浆糊。但是大家似乎都已经适应了,唉。


2月8日的测验:

T1.runner
稀里糊涂地就放掉了,实际上只需要分类讨论:
1.在不同子树内
2.在相同子树内
但是代码有些繁琐。
如果在考场上做这道题的话,关于在不同子树内的情况,
一个是这里写图片描述,一个是这里写图片描述这两种可能想不清楚。
第二个是代码不短,调试难度还是有。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100005;
const int inf=0x3f3f3f3f;
int n,head[N],to[2*N],nxt[2*N],num=0,C[N],Top=0,top=0,S[N],mx[N],mxer[N],dis[N];
int mxlen=0,st=0,ed=0,ans=inf;
bool vis[N],ins[N],flag=0,onc[N];
void build(int u,int v)
{
    num++;
    to[num]=v;
    nxt[num]=head[u];
    head[u]=num;
}
void getcircle(int u,int f)
{
    if(flag) return;
    vis[u]=1; ins[u]=1; S[++Top]=u;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i]; if(v==f) continue;
        if(ins[v])
        {
            flag=1;
            while(1)
            {
                C[++top]=S[Top]; onc[S[Top]]=1;
                ins[S[Top]]=0;
                Top--;
                if(S[Top+1]==v) break;
            }
        }
        else if(vis[v]) continue;
        else getcircle(v,u);
    }
    if(Top) Top--,ins[u]=0;
}       
bool check(int len,int s,int t,int opt)
{
    if(opt)
    {
        if(len>mxlen) return 1;
        if(len==mxlen&&s<st) return 1;
        if(len==mxlen&&s==st&&t<ed) return 1;
    }
    else 
    { 
        if(len<ans) return 1;
        if(len==ans&&s<st) return 1;
        if(len==ans&&s==st&&t<ed) return 1;
    }
    return 0;
}
void dfs(int u,int f)
{
    mx[u]=0,mxer[u]=u;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(onc[v]||v==f) continue;
        dfs(v,u);
        int len=mx[v]+mx[u]+1; int s=mxer[u],t=mxer[v];
        if(s>t) swap(s,t);
        if(check(len,s,t,1)) mxlen=len,st=s,ed=t;
        if(mx[u]<mx[v]+1||(mx[u]==mx[v]+1&&mxer[u]>mxer[v])) mx[u]=mx[v]+1,mxer[u]=mxer[v];
    }
}
void getans()
{
    for(int i=2;i<=top;i++) dis[C[i]]=dis[C[i-1]]+1;
//----opt 1.   2(n-1)-(dis[now]-dis[pre])-mx[now]-mx[pre]; 
    //         =2(n-1)-dis[now]-mx[now]+dis[pre]-mx[pre]    
    int L=-mx[C[1]]; int x=mxer[C[1]];// dis[pre]-mx[pre]
    for(int i=2;i<=top;i++)
    {
        int  u=C[i]; int s=mxer[u],t=x;
        int len=2*(n-1)+L-dis[u]-mx[u];
        if(s>t) swap(s,t);
        if(check(len,s,t,0)) ans=len,st=s,ed=t;
        if(dis[u]-mx[u]<L||(dis[u]-mx[u]==L && mxer[u]<x)) L=dis[u]-mx[u],x=mxer[u];
    }
//----opt 2.   2(n-1)-(top-(dis[now]-dis[pre]))-mx[now]-mx[pre]; 
    //         =2(n-1)+dis[now]-mx[now]-dis[pre]-mx[pre]-top      
    L=-mx[C[1]],x=mxer[C[1]];// -dis[pre]-mx[pre]
    for(int i=2;i<=top;i++)
    {
        int  u=C[i]; int s=mxer[u],t=x;
        int len=2*(n-1)+L+dis[u]-mx[u]-top;
        if(s>t) swap(s,t);
        if(check(len,s,t,0)) ans=len,st=s,ed=t;
        if(-dis[u]-mx[u]<L||(-dis[u]-mx[u]==L && mxer[u]<x)) L=-dis[u]-mx[u],x=mxer[u];
    }
}
int main()
{
    freopen("runner.in","r",stdin);
    freopen("runner.out","w",stdout);
    scanf("%d",&n); ans=inf;
    for(int i=1;i<=n;i++) 
    {
        int u,v; scanf("%d%d",&u,&v);
        build(u,v); build(v,u);
    }
    memset(ins,0,sizeof(ins));
    getcircle(1,1);
//---get the deepest point in each tree 
//---S and T in one tree
    for(int i=1;i<=top;i++) dfs(C[i],C[i]);
    ans=min(ans,(2*n-mxlen-top));
//---S ans T in different trees
    getans();
    printf("%d %d %d\n",ans,st,ed);
    return 0;
}

T2.longer
这是最亏的。
斜率优化要想到肯定是很容易,但是认为那样的复杂度可卡所以没有写,考试时花了大把时间去想有没有其他合理的做法,结果std就写的那个,mmp。
但是实际上在没有其他想法的时候,这种可以骗骗分的思路是可以写的。同时,在考场上大家都写了的那个理论复杂度有问题的做法,下来讨论发现那个做法确实是难以卡掉的。
如果要严谨的方法,可以二分弹栈的位置,决策点也可以二分去找。(最后想到了二分,但是没有想清楚,而且也没有时间了)

T3.knightmov
目前还不知道正解是什么,考场上大部分时间给了T2,最后写了T3。
我的想法是容斥,但是由于时间不够以及暂时还没有想到很多细节如何处理,我的判无解和无穷解的机制是有问题的,它会把一些正常情况也判成无解和无穷解。最后得了45’。


2月9日的测验:

实在是应该好好反省自己的考试时间规划。

T1.yist
实际上是一道比较简单的题,和之前做过的bzoj3771有些像。
但是考场上下意识就跳过了直接从T2开始看。
教训:要认真看过每道题的题面,在草稿纸上画一画有没有初步想法之后再决定从哪题开始,不能习惯性地/随性地安排顺序,头脑最初比较清晰的时候的安排,一定要慎重。
6=3+1+1+1
6=2+2+1+1
一个比较简单的处理就是安排顺序,例如先按从小到大排序,这样容斥起来非常有条理。

下午改题的时候没看sol自己想了做了,大概花了一个半小时多,中间差点漏了ab cd和ac bd会重复的情况。但是最终在讨论时还是少了一个细节就是2+2是四个相同的情况,所以第一次改是70’,静态查出来加上了。实际上这还是又忘了要先仔细静态查错这件事。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int MXN=10000007;
const int N=5005;
/*
    6=3+1+1+1
    6=2+2+1+1
*/
int one[MXN],two[2*MXN],a[N],n;
 LL ans1=0,ans2=0;
LL C(int n,int m)
{
    if(n<m) return 0;
    LL ret=1;
    for(int i=n;i>=n-m+1;i--) ret=1LL*ret*i;
    for(int i=2;i<=m;i++) ret/=(1LL*i);
    return ret;
}
int main()
{
    freopen("yist.in","r",stdin);
    freopen("yist.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),one[a[i]]++; //一个的
    sort(a+1,a+n+1); //get a
    for(int i=1;i<=n;i++) for(int j=1;j<i;j++) two[a[i]+a[j]]++; //两个的
    int last=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==last) continue; int x=a[i];  //ai是第一个等于s的
        LL ret=0;
        if(one[x]>=3) //3 1 1 1
        {

            for(int j=1;j<i;j++) //选了a[j]; 不同的三元组会被枚举3次
            {
                ret+=1LL*two[x-a[j]];//abc*3
                if(x>=2*a[j]) ret-=1LL*(one[x-a[j]-a[j]]-(3*a[j]==x)); //abb
            }
            ret/=3LL;
            ans1+=1LL*ret*C(one[x],3);
        }
        if(one[x]>=2) //2 2 1 1    ab cd
        {
            int La=0;  ret=0; LL cnt=0;
            for(int j=i-1;j>=1;j--)
            {
                if(a[j]==La) continue;
                if(x-a[j]>a[j]) break;
                LL cur=0;
                if(a[j]!=x-a[j]) cur=(1LL*one[a[j]]*one[x-a[j]]),ret+=(1LL*C(one[a[j]],2)*C(one[x-a[j]],2));
                else cur=C(one[a[j]],2),ret+=1LL*C(one[a[j]],4);
                ret+=(1LL*cur*cnt);
                cnt+=cur;
                La=a[j];
            }
            ans2+=1LL*ret*C(one[x],2);
        }
        last=a[i];
    }
    printf("%I64d\n",ans1+ans2);
    return 0;
}

T2.num

花了几乎所有时间而几乎没有分的一道题。
最初决定先做这道题的原因很简单:打表找规律先
谁知不知不觉就在上面耗完了考试时间。
确实,要随时提醒自己不要在一个状态上面陷得过久。
这里写图片描述

而我打表找规律得到的是,每一行是杨辉三角的n倍,因此后面的处理都直接按杨辉三角想了,
也就因此,难以看出那个至关重要的规律,因为它是针对原三角形(莱布尼兹调和三角的分母)的:

nklcm=lcm(nk+1,nk+2,...n) 第 n 行 前 k 个 数 的 l c m = l c m ( n − k + 1 , n − k + 2 , . . . n )

题目条件每一个都可能有用,不要轻易抛掉哪个。

不是没想到数据结构来维护各个质数的次数,但是没有这个转化还是很难,用40’算法对前40’打了个表,程序交的是表,但是cena居然收不上去,惨痛。

这个维护的方法还是比较巧妙的。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
const int mod=1000000007;
using namespace std;
const int N=100000;
int ptot=0,P[N+5],pri[N+5],is[N+5];
vector<int> pos[N+5],num[N+5],po[N+5];
int tail=0,root[N+5],val[N+5];
int Q,Ni,Ki,A,B,M,C[2*N+5],D[2*N+5];
struct node
{
    int ls,rs,sum;
    void init(){ls=rs=0,sum=1;}
}tr[N*100+5];
void shai()
{
    is[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!is[i]) pri[++ptot]=i,P[i]=i;
        for(int j=1;j<=ptot;j++)
        {
            int pp=pri[j];
            if(1LL*pp*i>N) break;
            is[pp*i]=1;
            P[pp*i]=pp;
            if(i%pp==0) break;
        }
    }
}
void insert(int pre,int &now,int lf,int rg,int pos)
{
    now=++tail,tr[now]=tr[pre];
    if(lf==rg) {tr[now].sum=val[lf]; return;}
    int mid=(lf+rg)>>1;
    if(pos<=mid) insert(tr[pre].ls,tr[now].ls,lf,mid,pos);
    else insert(tr[pre].rs,tr[now].rs,mid+1,rg,pos);
    tr[now].sum=(1LL*tr[tr[now].ls].sum*tr[tr[now].rs].sum)%mod;
}
int query(int nd,int lf,int rg,int L,int R)
{
    if(L<=lf&&rg<=R) return tr[nd].sum;
    int mid=(lf+rg)>>1;
    int ret=1;
    if(L<=mid) ret=(1LL*ret*query(tr[nd].ls,lf,mid,L,R))%mod;
    if(R>mid) ret=(1LL*ret*query(tr[nd].rs,mid+1,rg,L,R))%mod;
    return ret;
}
int main()
{
    freopen("num.in","r",stdin);
    freopen("num.out","w",stdout);
    shai();
    root[0]=0;tr[0].init();
    val[1]=1; insert(root[0],root[1],1,N,1);
    for(int i=2;i<=N;i++)
    {
        int tmp=i; val[i]=i;
        insert(root[i-1],root[i],1,N,i);
        while(tmp!=1)
        {
            int pi=P[tmp],cnt=0,mi=1,Mi,Cnt;
            for(;tmp%pi==0;tmp/=pi) cnt++,mi*=pi; Mi=mi,Cnt=cnt;
            int sz=pos[pi].size();
            for(int j=sz-1;j>=0;j--)
            {
                if(!cnt) break;
                if(num[pi][j]<=cnt)
                { 
                    val[pos[pi][j]]/=po[pi][j];
                    insert(root[i],root[i],1,N,pos[pi][j]);
                    cnt-=num[pi][j];
                    mi/=po[pi][j];
                    pos[pi].pop_back();
                    po[pi].pop_back();
                    num[pi].pop_back();
                }
                else
                {
                    val[pos[pi][j]]/=mi;
                    insert(root[i],root[i],1,N,pos[pi][j]);
                    po[pi][j]/=mi;
                    num[pi][j]-=cnt;
                    break;
                }
            } 
            pos[pi].push_back(i);
            po[pi].push_back(Mi);
            num[pi].push_back(Cnt);
        }
    }
    scanf("%d",&Q);
    scanf("%d%d",&Ni,&Ki);
    scanf("%d%d%d",&A,&B,&M);
    for(int i=1;i<Q;i++) scanf("%d",&C[i]);
    for(int i=1;i<Q;i++) scanf("%d",&D[i]);
    int ans=query(root[Ni],1,N,Ni-Ki+1,Ni);
    printf("%d\n",ans);
    for(int i=1;i<Q;i++)
    {
        Ni=(1LL*A*ans%M+C[i]%M)%M+1;
        Ki=(1LL*B*ans%Ni+D[i]%Ni)%Ni+1;
        ans=query(root[Ni],1,N,Ni-Ki+1,Ni);
        printf("%d\n",ans);
    }
    return 0;
}

T3.sanrd
题解写的比较草率,没看懂。


考试方面,我觉得自己的问题问题非常大。
时间安排这方面需要再仔细分以下,暂定:
7:40-8:10读题
不能到9:10为止还不开始做题。
9:10如果可能去切第一题或者正在切第一题。
写完一题拍着走。
之后想清楚有没有时间T2,T3都涉猎,不然集中选一道攻克,剩下的也要写暴力
最后留时间至少半小时检查。


真的觉得自己码力不行。现在不能凌晨起来,不过寒假的话,只要有CF的比赛都打算去打。


最近心情不佳。
每天还是挺孤独的,而且对自己没什么自信吧,还是挺难受。有时候真想痛痛快快哭一场。
不过,就算现在天天垫底也不要被打倒!
总之,做好自己手上的事,做好能做的事总会有进步的!
加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值