20191021考试总结

第一题:病毒分裂

题目描述: A学校的实验室新研制出了一种十分厉害的病毒。由于这种病毒太难以人工制造了,所以专家们在一开始只做出了一个这样的病毒。这个病毒被植入了特殊的微型芯片,使其可以具有一些可编程的特殊性能。最重要的一个性能就是,专家们可以自行设定病毒的分裂能力K,假如现在有x个病毒,下一个分裂周期将会有Kx个一模一样的病毒。你作为该实验室的数据分析员,需要统计出在分裂到第N个周期前,一共有多少个病毒单体进行了分裂。一开始时总是只有一个病毒,这个局面算作第一个周期。由于答案可能很大,专家们只需要你告诉他们对给定的P 取模后的答案。
【输入格式】一行三个整数,依次是K, N, P。
【输出格式】一行一个整数,你的答案(对P 取模)
1 < n < 10^18,1 < k,p < 2^32(p不一定是素数)

成绩:AC

题解:根据题意答案为:k^0+k^1+k^2+…+k^(n-2),因为p不一定为素数无法求逆元,所以用二分法求和。

分析:这道题并没有花多少时间,很快就做出来了,正常的第一题发挥。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned long long ll;
ll n,k,mod;
ll qpow(ll tmp,ll p){
    ll res=1ll;
    while(p){
        if(p&1) res=res*tmp%mod;
        tmp=tmp*tmp%mod,p>>=1;
    }
    return res;
}
ll f(ll x,ll p){
    if(p==1) return x;
    ll mid=p>>1,tep=f(x,mid);
    ll ret=qpow(x,mid);
    ll ans=tep*(ret+1)%mod;
    if(p&1) ans=(ans+qpow(x,p))%mod;
    return ans;
}
int main(){
    freopen("split.in","r",stdin);
    freopen("split.out","w",stdout);
    cin>>k>>n>>mod;
    if(n==2) cout<<1%mod<<endl;
    else cout<<(f(k%mod,n-2)+1)%mod<<endl;
}
/*
5 3 7
*/
/*
2 8 23
*/

第二题:疫情延迟

题目描述:由于A 学校生物实验室里那个不负责的数据分析员,实验室的病毒威力被错误估算,导致了可怕的病毒泄漏,现在病毒即将在校园内传播开来。校园里一共有n个建筑物,生物实验室总是位于一号建筑物且在0时刻受到病毒入侵。这n个建筑物由m 条单向道路相连(也有可能有建筑物被孤立)。每条道路有两个信息:它的长度,它是多少年前修建的。当一个建筑物被病毒入侵,从被入侵的时刻起,病毒会从所有由这个建筑物通向其他建筑物的道路按着这条道路的方向以1个单位每秒的速度行进。校长得知这个事情后,决定放弃这个学校逃跑。校长总是位于编号为n的行政楼,从零时刻开始需要共T秒来逃出行政楼,且逃出行政楼即视为逃出了这个学校。也就是说,如果病毒入侵行政楼的时间不小于T,则校长能够成功逃离。有些时候,校长没有足够的时间逃离,因为病毒到达行政楼的时间太快了。为了让校长能够逃离学校,不得不拆除校园内的一些道路以延缓行政楼的被入侵时间(拆除道路视为在0时刻被拆拆的道路全部消失)。当然,如果使得病毒根本无法到达行政楼,也是可以的。但是,拆除道路会影响学校的历史气息,且破坏程度定义为拆除的道路中最古老的一条的年龄。请求出保证校长能够安全撤离的情况下,最小的破坏程度。
【输入格式】
第一行包含三个整数:n, m, T。
接下来m行,每行描述一条有向道路。每行4个整数
si, ti, Li, Yi,分别表示这条道路的起点,终点,长度,这条道路的年龄。
【输出格式】
如果不需要拆除任何道路,输出一行两个数:-1和行政楼的被感染时刻(当然这个时刻大于等于T),以空格隔开。否则输出一行包含一个数:最小的破坏程度。

成绩:10 °(°ˊДˋ°) °

题解:二分+spfa或堆优化dijkstra。

分析:因为二分的是最长的一条路,所以每次二分后重新建图时因是比当前二分mid值大的路才可以走,(然而我写反了)

//注意long long
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int N=20000+10;
const int M=100000+10;
const ll inf=1ll<<50;
inline void getint(int&num){
    char c;int flag=1;num=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
inline void getint(ll&num){
    char c;int flag=1;num=0ll;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
struct node{
    int u,v,y;ll w;
    bool operator < (const node&x)const{
        return y<x.y;
    }
}e[M];
int n,m,cnt;
int fir[N],tar[M],nxt[M];
ll T,dis[N],w[M];
bool in[N];
queue<int> q;
void link(int a,int b,ll c){
    tar[++cnt]=b,w[cnt]=c;
    nxt[cnt]=fir[a],fir[a]=cnt;
}
ll spfa(){
    memset(in,0,sizeof in);
    for(int i=1;i<=n;i++) dis[i]=inf;
    while(!q.empty()) q.pop();
    dis[1]=0ll,q.push(1);
    while(!q.empty()){
        int t=q.front();
        q.pop(),in[t]=0;
        for(int i=fir[t];i;i=nxt[i])
            if(dis[tar[i]]>dis[t]+w[i]){
                dis[tar[i]]=dis[t]+w[i];
                if(!in[tar[i]])
                    in[tar[i]]=1,q.push(tar[i]);
            }
    }
    return dis[n];
}
void build(int up){
    memset(fir,0,sizeof fir),cnt=0;
    for(int i=up;i<=m;i++)
        link(e[i].u,e[i].v,e[i].w);
}
int divide(int l,int r){
    if(l==r) return l;
    int mid=(l+r+1)>>1;build(mid);
    if(spfa()>=T) return divide(l,mid-1);
    else return divide(mid,r);
}
int main(){
    freopen("delay.in","r",stdin);
    freopen("delay.out","w",stdout);
    getint(n),getint(m),getint(T);
    for(int i=1;i<=m;i++){
        getint(e[i].u),getint(e[i].v);
        getint(e[i].w),getint(e[i].y);
    }
    sort(e+1,e+m+1);
    build(1);ll tep=spfa();
    if(tep>=T){
        cout<<"-1"<<' '<<tep<<endl;
        return 0;
    }
    printf("%d\n",e[divide(1,m)].y);
}
/*
5 5 15
1 2 6 35
2 4 8 40
1 3 6 45
3 4 3 25
4 5 5 50
*/
/*
3 2 10
1 2 5 30
2 3 6 50
*/

第三题:避难向导

题目描述:“特大新闻,特大新闻!全国爆发了一种极其可怕的病毒,已经开始在各个城市 中传播开来!全国陷入了巨大的危机!大量居民陷入恐慌,想要逃到其它城市以 避难!经调查显示,该病毒来自于C 市的A 学校的一次非法的……” “哎。”你关上电视,叹了口气。作为A 学校的校长,你一天前为了保命,独自 逃离了A 学校,抛弃了全校师生,包括那个曾经帮你计算并拆除道路的工程师。 你良心受到了巨大的谴责,因此决定做出一些补救,回答一些逃难的人提出的询 问。 已知该国一共有n 个城市,并且1 号城市是首都。(n-1)条双向的公路连接这些 城市,通过这些公路,任意两个城市之间存在且仅存在一条路径。每条公路有一 个长度。如果一个城市只与一条公路相连,则称它为边境城市。 该国政府有一个奇怪的规定:每个城市有一个封闭系数di,定义di 为离这个城 市最远的边境城市到这个城市的距离。市民们认为,一个城市的安全系数Si 和 它的封闭系数有很重要的联系。a,b,c 是该国的幸运数字,所以大家公认一个 城市的安全系数Si = (di + a) * b mod c。 市民们一共会提出m 次询问。每个询问包含三个信息,xi,yi 和qi。xi 是询问 者所在的城市编号。你要为这个询问者在xi 到yi 的必经之路上找出一个离xi 最近的避难城市,并且要求这个避难城市的安全系数大于等于qi。如果存在这 样的城市(包含xi 和yi),则输出城市编号,否则输出一行包括一个数-1。

成绩:AC

题解:倍增lca同时维护一个dp[i][j]表示i与它上面的2^j个祖先中,安全系数最大的值,每次询问先查出lca,然后先从x向上到lca,找满足题意最靠下的点,在从y向上找满足题意最靠上的点。
另k=dep[lca]-dep[x];k=2^a1+2^a2+…找到最下方dp[s][i]>=q的一段,在这一段中二分。(y找最上方的一段)

分析:这是一道做过的原题,然而写的时候还是遇到了很多困难(手动尴尬),也调试了好一阵,还好最后还是调试出来了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll; 
const int N=100000+10;
const int M=200000+10;
const int LCA=20;
inline void getint(int&num){
    char c;int flag=1;num=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
inline void getint(ll&num){
    char c;int flag=1;num=0ll;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
int n,T,x,y,cnt,dep[N];
int root1,root2,tep,anc;
int fir[N],tar[M],nxt[M];
int f[N][LCA+5];
ll a,b,c,q,safe[N],w[M];
ll dis[N][2],dp[N][LCA+5];
void link(int a,int b,ll c){
    tar[++cnt]=b,w[cnt]=c;
    nxt[cnt]=fir[a],fir[a]=cnt;
}
void dfs(int x,int fa,bool f){
    if(dis[root1][f]<=dis[x][f])
        root1=x;
    for(int i=fir[x];i;i=nxt[i])
        if(tar[i]!=fa){
            dis[tar[i]][f]=dis[x][f]+w[i];
            dfs(tar[i],x,f);
        }
}
void Dfs(int x,int fa){
    f[x][0]=fa;
    for(int i=fir[x];i;i=nxt[i])
        if(tar[i]!=fa){
            dep[tar[i]]=dep[x]+1;
            Dfs(tar[i],x);
        }
}
inline void init(){
    for(int i=1;i<=n;i++)
        dp[i][0]=max(safe[i],safe[f[i][0]]);
    for(int i=1;i<=LCA;i++)
        for(int j=1;j<=n;j++){
            f[j][i]=f[f[j][i-1]][i-1];
            dp[j][i]=max(dp[j][i-1],dp[f[j][i-1]][i-1]);
        }
}
int getk(int x,int k){
    if(!k) return x;
    for(int i=LCA;i>=0;i--)
        if(k&(1<<i)) x=f[x][i];
    return x;
}
int getd(int x,int d){
    return getk(x,dep[x]-d);
}
int lca(int u,int v){
    if(dep[u]!=dep[v]){
        int mind=min(dep[u],dep[v]);
        u=getd(u,mind),v=getd(v,mind);
    }
    if(u==v) return u;
    for(int i=LCA;i>=0;i--)
        if(f[u][i]!=f[v][i])
            u=f[u][i],v=f[v][i];
    return f[u][0];
}
void find_x(int x,int y){
    int k=dep[x]-dep[y];
    if(!k){
        if(safe[x]>=q)
            tep=x;
        return ;
    }
    int st=-1,up;
    for(int i=0;i<=LCA;i++)
        if(k&(1<<i)){
            if(dp[x][i]>=q){
                st=x,up=i;
                break ;
            }
            x=f[x][i];
        }
    if(st<0) return ;
    while(up){
        if(dp[st][up-1]>=q) up--;
        else st=f[st][--up];
    }
    if(safe[st]>=q) tep=st;
    else if(safe[f[st][0]]>=q) tep=f[st][0];
}
void find_y(int x,int y){
    int k=dep[x]-dep[y];
    if(!k){
        if(safe[x]>=q)
            tep=x;
        return ;
    }
    int st=-1,up;
    for(int i=LCA;i>=0;i--)
        if(k&(1<<i)){
            if(dp[x][i]>=q)
                st=x,up=i;
            x=f[x][i];
        }
    if(st<0) return ;
    while(up){
        if(dp[f[st][up-1]][up-1]>=q)
            st=f[st][--up];
        else up--;
    }
    if(safe[st]>=q) tep=st;
    else if(safe[f[st][0]]>=q) tep=f[st][0];
}
int main(){
    //freopen("shelter.in","r",stdin);
    //freopen("shelter.out","w",stdout);
    getint(n),getint(T);
    getint(a),getint(b),getint(c);
    for(int i=1;i<n;i++){
        getint(x),getint(y),getint(q);
        link(x,y,q),link(y,x,q);
    }
    dfs(1,0,0);
    dis[root1][1]=0,dfs(root2=root1,0,1);
    dis[root1][0]=0,dfs(root2=root1,0,0);

    for(int i=1;i<=n;i++){
        ll d=max(dis[i][0],dis[i][1]);
        safe[i]=(d+a)*b%c;
    }
    Dfs(1,0);
    init();
    while(T--){
        getint(x),getint(y),getint(q);
        anc=lca(x,y),tep=-1;
        find_x(x,anc);
        if(tep<0) find_y(y,anc);
        printf("%d\n",tep); 
    }
}
/*
7 6 5 6 20
1 2 4
2 4 2
2 5 3
1 3 5
3 6 6
6 7 7
7 5 15
3 4 5
5 4 2
4 5 2
6 6 10
3 5 19
*/

总结:这套题很简单,然而分数却不是很高,主要是第二题的失误,一眼正解之后,检查就没那么仔细(感觉肯定没问题)。而且因为第二题对拍不太方便,就没有对拍,也是受惯性思维的影响,一般二分都是小于(谁知道。。。)。
即使觉得题目很简单,也要认真检查。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值