10-24

T1:已知每一个病毒会在下一秒分裂成k个病毒,开始时只有一个病毒,求第n秒前有多少个病毒发生了分裂,答案对p取模。1<k,p<2^32,n<10^18

如果n==2,那么答案是1

如果n==3,那么答案是1+1*k

那么n秒后,就会有k^0+k^1+k^2+......+k^(n-2)

由于数据范围问题,我们要用到分制的思想,再加上快速幂就ok了

#include<bits/stdc++.h>
#define LL long long
using namespace std;

LL K,N,P;

LL quick(LL a,LL b){
    LL ans=1,t=a;
    while(b){
        if(b&1) ans=(ans*t)%P;
        b>>=1;
        t=(t*t)%P;
    }
    return ans;
}

LL slove(LL k,LL n){
    if(n==1) return k;
    LL t1=slove(k,n>>1);
    LL t2=quick(k,n>>1);
    LL ans;
    if(n&1) ans=(t1%P+(t1*t2)%P+quick(k,n)%P)%P;
    else ans=(t1%P+(t1*t2)%P)%P;
    return ans;
}

int main(){
    freopen("split.in","r",stdin);
    freopen("split.out","w",stdout);
    
    cin>>K>>N>>P;
    LL ans=(slove(K,N-2)+1)%P;
    cout<<ans<<endl;
    
    fclose(stdin); fclose(stdout);
    return 0;
}

T2:给你一个图,边有时间和年龄两种权值,去掉一些边,令从1到n的时间>T(令1和n不连通也行),并要求破坏的路的年龄最大的最小,求这个年龄,如果不需要去掉边,则输出-1和1到n的时间。

emmmm令最大值最小,二tm分走起。

二分答案ans,做spfa,图中年龄<=ans的边都是不能走的(去掉了),得出答案即可

#include<bits/stdc++.h>
using namespace std;

struct hehe{
    int y,next,v,c;          //c表示年代,v表示长度
}e[100100];
int lin[20100],len=0,ye[100100],n,m,T,dis[20100];
bool vis[20100];
queue<int> q;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch-'0'); ch=getchar();}
    return x*f;
}

inline void insert(int x,int y,int v,int c){
    e[++len].next=lin[x]; lin[x]=len;
    e[len].y=y; e[len].v=v; e[len].c=c;
}

void spfa(int maxx){
    q.push(1);
    memset(dis,10,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1]=0; vis[1]=1;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=lin[x];i;i=e[i].next){
            if(e[i].c<=maxx) continue;
            int y=e[i].y;
            if(dis[x]+e[i].v<dis[y]){
                dis[y]=dis[x]+e[i].v;
                if(!vis[y]){
                    q.push(y);
                    vis[y]=1;
                }
            }
        }
        vis[x]=0;
    }
}

int main(){
    freopen("delay.in","r",stdin);
    freopen("delay.out","w",stdout);
    
    n=read(); m=read(); T=read();
    int x,y,v,c;
    for(int i=1;i<=m;++i){
        x=read(); y=read(); v=read(); c=read();
        insert(x,y,v,c);
        ye[i]=c;
    }
    sort(ye+1,ye+m+1);
    spfa(0);
    if(dis[n]>=T){
        cout<<"-1"<<' '<<dis[n]<<endl;
        return 0;
    }
    int l=1,r=m,mid;
    while(l+1<r){
        mid=(l+r)>>1;
        spfa(ye[mid]);
        if(dis[n]<T) l=mid;
        else r=mid;
    }
    spfa(ye[r]);
    if(dis[n]<T || dis[n]==dis[0]) l=r;
    cout<<ye[l]<<endl;
    
    fclose(stdin);fclose(stdout);
    return 0;
}

T3:给出一棵树,根节点为1。树上每个节点的权值通过以它为端点的树上最长链通过带系数的计算获得。给出m个询问,每个询问给出三个信息 x, y, q,求从节点 x到 y的树上路径中离xi最近的同时权值大于等于 q(以下简称为合法)的节点的编号,不存在则输出-1。

那么这个题主要就是要解决两个问题,一个是求最长链,一个是求两点间离其中一点最近的合法的点。

对于第一个问题,有四种解决方法,floyd,bfs,树形dp。对应的复杂度分别是o(n^3),o(n^2),o(n)。

对于第二个问题,容易想到的比较简单的o(n)的算法是基于每个询问的起点做bfs,对于每一个点,需要保存路径中离起点最近的合法的点的编号,结合o(n)的求最长链的方法,期望得分25~30

剩下的东西我不会了,考试的时候也就拿了30。

第二题交的时候忘了把注释取消掉了orz,又犯了这种sb错误。

posted @ 2017-10-25 17:06  assassin灬  阅读(181)  评论(0编辑  收藏  举报