[赛后总结]2020.2.29考试总结

最近考试渐渐多起来了,考试总结肯定是有必要的了…

总述

总的来说考的确实不够理想…
第一题花了我太多的时间,主要的原因是调试时间太长了。[顺带说一个笑话,我在复制样例的时候不小心把页码给复制上去了,然后调试了整整一个多小时(我以为那东西是我输出的调试信息),百思不得其解…]。
然后T2,T3就没什么时间做了…
T2最开始看以为是道签到题,直接跑 m m m次最短路就做完了,然后写完之后才发现自己写了个10分暴力[顺带吐槽一下这套题为什么暴力分这么少…]。
然后发现满分做法也不难,只用保留最短路径树上的边跑最短路就可以了,写到一半就差点被翻转边的操作给逼疯了[链式前向星存图做类似边翻转查值之类的操作的时候真的很不方便…]。
后来终于放弃了了链式前向星,直接用二维数组重新写,不得不说写起来舒服多了:)
然后写着写着发现自己把自己的暴力给改没了:)
为了保命只好又着急地把暴力给补上。
这时候就只剩下40min了。
无奈之下只好看看T3有没有什么有趣的部分分。
以为自己可以打出一个 O ( n 3 ) O(n^3) O(n3)的dp算法,结果半天都没什么思路…
最后20min O ( n m ) O(nm) O(nm) 10分暴力dp走人…
等到最后上交题目的时候才发现T2有重边…心态爆炸…

最终得分: 100 + 0 + 10 100+0+10 100+0+10
改题的时候还发现T2数组也开小了

莲花灯(lamp)

线段树分治+线性基

这个月刚学的线段树分治,还是做了5-6道题目了。但是实际考试中还是很不熟练。
原题目显然就是在要求我们动态加入删除线性基中的某些元素然后做询问。
我们知道线性基本身是没有可删除性的,但是我们可以考虑使用像并查集一样的保存之前的版本以实现可回退化。
于是我们就直接模仿线段树分治维护并查集的方法维护线性基就可以了。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<vector>
#include<queue>
#include<bitset>
#include<map>
using namespace std;

#define LL long long
#define DB double
#define MOD 1000000007
#define Pr pair<int,int>
#define X first
#define Y second
#define MAXN 100000
#define eps 1e-10
#define INF 1000000000
#define inf 100000000000000000LL
#define mem(x,p) memset(x,p,sizeof(x))

LL read(){
  LL x=0,F=1;char c=getchar();
  while(c<'0'||c>'9'){if(c=='-')F=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
  return x*F;
}
int add(int a,int b){return (a+b>=MOD)?a+b-MOD:a+b;}
int dec(int a,int b){return (a-b<0)?a-b+MOD:a-b;}
int mul(int a,int b){return 1LL*a*b%MOD;}
int fst_pow(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=mul(res,a);
        a=mul(a,a);
        b>>=1;
    }return res;
}
int inv(int a){return fst_pow(a,MOD-2);}

int n,m,k;char s[MAXN+5];
LL ans[MAXN+5],Q[MAXN+5];
map<LL,int> dic;
struct node{
    int L,R;LL num;
};

LL Cg(){
    LL res=0;
    for(int i=0;i<n;i++)
    if(s[i]-'0')res|=1LL<<(n-i-1);
    return res;
}
struct Base{
    LL d[34];
    void init(){mem(d,0);}
    void Insert(LL x){
        for(int i=n-1;i>=0;i--)
        if(x&(1LL<<i)){
            if(d[i])x^=d[i];
            else {d[i]=x;return ;}
        }
    }
    int Query(LL x){
        x=(1LL<<n)-1-x;
        for(int i=n-1;i>=0;i--)
        if(x&(1LL<<i)){
            if(!d[i])return 0;
            x^=d[i];
        }return 1;
    }
}D[20];

struct Seg_tree{
    vector<LL> G[(MAXN<<1)+5];
    #define mid ((l+r)>>1)
    #define gid(l,r) ((l+r)|(l!=r))
    void Insert(int l,int r,node d){
        if(d.L>r||l>d.R)return ;
        int x=gid(l,r);
        if(d.L<=l&&d.R>=r){
            G[x].push_back(d.num);
            return ;
        }
        Insert(l,mid,d),Insert(mid+1,r,d);
    }
    void solve(int l,int r,int d){
        D[d]=D[d-1];int x=gid(l,r);
        for(int i=0;i<G[x].size();i++)
            D[d].Insert(G[x][i]);
        if(l==r){
            ans[l]=D[d].Query(Q[l]);
            return ;
        }
        solve(l,mid,d+1),solve(mid+1,r,d+1);
    }
}T;

int main(){
    freopen("lamp.in","r",stdin);
    freopen("lamp.out","w",stdout);
    n=read(),m=read(),k=read();
    scanf("%s",s);Q[0]=Cg();
    for(int i=1;i<=m;i++){
        scanf("%s",s);dic[Cg()]=0;
    }
    for(int i=1;i<=k;i++){
        int opt=read();scanf("%s",s);
        LL num=Cg();Q[i]=Q[i-1];
        cerr<<
        if(opt){
            if(dic.count(num)){
                T.Insert(0,k,(node){dic[num],i-1,num});
                dic.erase(num);
            }else dic[num]=i;
        }else Q[i]=num;
    }
    map<LL,int>::iterator it;
    for(it=dic.begin();it!=dic.end();it++)
        T.Insert(0,k,(node){it->Y,k,it->X});
    T.solve(0,k,1);
    for(int i=0;i<=k;i++)
    printf("%s\n",ans[i]?"YES":"NO");
}

风穿巷(lane)

最短路径树

这题其实是一道很简单很模板的题目,但是因为各种各样的细节还有绑点成为了一道坑人的毒瘤题。

玲珑塔(tower)

拉格朗日插值

简单但是想不到的题目…可能是类似的题目做少了吧…
做法很简单,所以贴篇题解就跑了:)
在这里插入图片描述

/*Lower_Rating*/
/*probaility*/
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<vector>
#include<queue>
#include<bitset>
#include<map>
using namespace std;

#define LL long long
#define DB double
#define MOD 998244353
#define Pr pair<LL,int>
#define X first
#define Y second
#define MAXN 4000
#define MAXM 50000
#define eps 1e-10
#define INF 1000000000000
#define mem(x,p) memset(x,p,sizeof(x))

LL read(){
  LL x=0,F=1;char c=getchar();
  while(c<'0'||c>'9'){if(c=='-')F=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
  return x*F;
}
int add(int a,int b){return (a+b>=MOD)?a+b-MOD:a+b;}
int dec(int a,int b){return (a-b<0)?a-b+MOD:a-b;}
int mul(int a,int b){return 1LL*a*b%MOD;}

int n,x[MAXN+5];LL m,c[MAXN+5];
int dp[MAXN+5][MAXN+5],ans,siz[MAXN+5],D,inv[MAXN+5];
vector<int> G[MAXN+5];
void dfs1(int x){
    siz[x]=1;
    for(int i=0;i<G[x].size();i++)
    {int v=G[x][i];dfs1(v);siz[x]+=siz[v];}
}
void dfs2(int x){
    int res,sum=0;
    for(int i=0;i<G[x].size();i++)
    {int v=G[x][i];dfs2(v);}
    for(int j=1;j<=D;j++){
        res=1;
        for(int i=0;i<G[x].size();i++){
            int v=G[x][i];
            res=mul(res,dp[v][j]);
        }
        sum=add(sum,res);
        dp[x][j]=sum;
    }
}
int main()
{
    freopen("tower.in","r",stdin);
    freopen("tower.out","w",stdout);
    n=read(),m=read();
    inv[0]=inv[1]=1;
    for(int i=2;i<=n;i++)inv[i]=mul(dec(MOD,MOD/i),inv[MOD%i]);
    for(int i=1;i<=n;i++){
        x[i]=read(),c[i]=read();
        if(x[i])G[x[i]].push_back(i);
    }
    ans=1;
    for(int i=1;i<=n;i++)
    if(c[i]){
        dfs1(i),D=siz[i]+1,dfs2(i);
        int X0=(m-c[i]+1)%MOD,res=0;
        for(int j=1;j<=D;j++){
            int Y=dp[i][j];
            for(int k=1;k<=D;k++)
            if(j>k)Y=mul(Y,mul(dec(X0,k),inv[j-k]));
            else if(j<k)Y=mul(Y,mul(dec(X0,k),MOD-inv[k-j]));
            res=add(res,Y);
        }
        ans=mul(ans,res);
    }
    printf("%d",ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值