前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NOIP2019模拟赛(十)06.02

NOIP2019模拟赛(十)06.02

作者头像
yzxoi
发布2022-09-19 12:40:43
2770
发布2022-09-19 12:40:43
举报
文章被收录于专栏:OI

NOIP2019模拟赛(十)06.02

Link

NOIP2019模拟赛(十)06.02

A. transfer

题意

n个小孩,他们会进行t轮游戏。一开始,鲜花在第一个孩子手里,每轮游戏持有鲜花的小孩可以把鲜花传递给除了自己以外的任意一个小孩。那么,一共有多少种传递方法,可以让鲜花在游戏结束时回到第一个小孩上呢? 对于100%的数据,n,t \leq 10^{18}

思路

每一轮,每个小孩都可以传递给另外一个小孩,那么就有n-1种传递方法。 有t轮,所以总共有(n-1)^t种传递方法。 每种传递方法的概率都是相同的,所以传递给第一个孩子的可能性为\frac{(n-1)^t}{n}。 注意,n,t的范围都很大,所以需要快速幂+乘法逆元。 对于NOIPPJ等级的我,只需要明白:费马小定理:当 p 为素数时, a^{p-1}=1 (mod p) 。那么 a*a^{p-2}=1 (mod p) 。即可。

Code

代码语言:javascript
复制
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define int long long
#define mod 1000000007
using namespace std;
int read(){
    char ch=getchar();int res=0,f=1;
    while(ch<'0'ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else write(x/10),putchar(x%10+'0');
}
int n,t;
int fpow(int a,int b){//快速幂
    int res=1;
    while(b){
        if(b%2==1) res=(res*a)%mod;
        a=(a*a)%mod,b>>=1;
    }
    return res;
}
int ans;
signed main(){
    n=read();t=read();n%=mod;
    if(t==1){
        puts("0");
        return 0;
    }
    ans=fpow(n-1,t-1);
    if(t%2==1) ans=((ans-1)*(n-1))%mod;//分奇偶讨论
    else ans=((ans+1)*(n-1))%mod;
    ans=(ans+mod)%mod;
    ans=ans*fpow(n,mod-2)%mod;//乘法逆元
    write(ans);
    return 0;
}

B. minecraft

题意

不要问我为什么这么懒就放一个pdf

思路

首先O(n^2)求出每个点到其他点的距离:sqrt({(x_1-x_2)}^2+{(y_1-y_2)}^2)-(z_1+z_2) 然后跑一遍最短路就好了。 但是二分答案来check也行。

Code

代码语言:javascript
复制
#include<bits/stdc++.h>
#define eps 1e-8
#define int long long
#define sqr(x) ((x)*(x))
using namespace std;
int read(){
    char ch=getchar();int res=0,f=1;
    while(ch<'0'ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else write(x/10),putchar(x%10+'0');
}
int n,s,t,vis[5010];
double f[5010][5010],Max,ans;
map<string,int> mp;
string tmp;
struct node{
    int x,y,z;
}a[5010];
double dist(int i,int j){
    return ((double)sqrt((double)((double)sqr(a[i].x-a[j].x)+(double)sqr(a[i].y-a[j].y)))-(double)(a[i].z+a[j].z));
}
queue<int> q;
bool check(double x){
    memset(vis,0,sizeof(vis));
    while(!q.empty()) q.pop();
    q.push(s);vis[s]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=1;i<=n;i++){
            if(vis[i]==0&&f[u][i]<=x){
                q.push(i);
                vis[i]=1;
                if(i==t) return 1;
            }
        }
    }
    return 0;
}
signed main(){
    n=read();
    for(int x,y,z,i=1;i<=n;i++){
        cin>>tmp;a[i].x=read();a[i].y=read();a[i].z=read();
        mp[tmp]=i;
    }
    cin>>tmp;s=mp[tmp];
    cin>>tmp;t=mp[tmp];
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            f[i][j]=f[j][i]=((dist(i,j)<0.0)?0.0:dist(i,j));
            Max=max(Max,f[i][j]);
        }
    }
    memset(vis,0,sizeof(vis));
    double l=0.0,r=Max,mid;
    while(r-l>=eps){
        mid=(l+r)/2.0;
        if(check(mid)) ans=mid,r=mid-eps;
        else l=mid+eps;
    }
    printf("%.6lf\n",ans);
    return 0;
}

C. rewrite

题意

对于一片森林,有两个操作: 1. 输入x,y x,y 两点连通,并且把他们的权值修改为\frac{⌊Vx+Vy⌋}{2},若x,y已经连通,则忽略此操作。 2.查询 x,y 两点之间的唯一路径上有多少种不同的点权,若x,y 此时还不连通,输出-1

思路

开一个 60 位的二进制,某一位为 1 就表示有这种颜色,然后用线段树维护区间信息就好了,每次合并或者查询就是一个二进制“或”的操作。 当然,用LCT与树剖都可以。

Code

代码语言:javascript
复制
#include<bits/stdc++.h>
#define int long long
#define MAXN 100010*2
using namespace std;
int read(){
    char ch=getchar();int res=0,f=1;
    while(ch<'0'ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
    return res*f;
}
void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x+'0');
    else write(x/10),putchar(x%10+'0');
}
int n,m,op,u,v;
int fa[MAXN];
int getfa(int x){
    return x==fa[x]?x:fa[x]=getfa(fa[x]);
}
class LinkCutTree{
    public:
        struct node{
            int f,c[2],v,xs,tag,xx;
        }t[300010];
        bool Isroot(int x){
            int y=t[x].f;
            return !(t[y].c[0]==xt[y].c[1]==x);
        }
        void Upd(int x){
            t[x].xs=(1ll<<t[x].v)t[t[x].c[0]].xst[t[x].c[1]].xs;
        }
        void Psd(int x){
            if(t[x].tag){
                swap(t[x].c[0],t[x].c[1]);
                if(t[x].c[0])t[t[x].c[0]].tag^=1;
                if(t[x].c[1])t[t[x].c[1]].tag^=1;
                t[x].tag=0;
            }
        }
        void Rotate(int x){
            int y=t[x].f,z=t[y].f;
            Psd(y);
            Psd(x);
            int c=t[y].c[1]==x;
            if(!Isroot(y)){
                int gc=t[z].c[1]==y;
                t[z].c[gc]=x;
            }
            t[x].f=z;
            t[y].c[c]=t[x].c[c^1];
            t[t[x].c[c^1]].f=y;
            t[x].c[c^1]=y;
            t[y].f=x;
            Upd(y);
            Upd(x);
        }
        void Splay(int x){
            Psd(x);
            while(!Isroot(x)){
                int y=t[x].f,z=t[y].f;
                if(Isroot(y))Rotate(x);
                else{
                    Psd(z);
                    Psd(y);
                    int c=t[y].c[1]==x,gc=t[z].c[1]==y;
                    if(c==gc)Rotate(y);
                    else Rotate(x);
                    Rotate(x);
                }
            }
        }
        void Access(int x,int lst){
            if(!x)return;
            Splay(x);
            t[x].c[1]=lst;
            Upd(x);
            Access(t[x].f,x);
        }
        void Makeroot(int x){
            Access(x,0);
            Splay(x);
            t[x].tag^=1;
        }
        void Split(int x,int y){
            Makeroot(x);
            Access(y,0);
            Splay(y);
        }
        int Findroot(int x){
            Access(x,0);
            Splay(x);
            Psd(x);
            while(t[x].c[0]){
                x=t[x].c[0];
                Psd(x);
            }
            Splay(x);
            return x;
        }
        int Link(int x,int y){
            Makeroot(x);
            if(Findroot(y)!=x){
                t[x].f=y;
                return 1;
            }
            return 0;
        }
        void Cut(int x,int y){
            Makeroot(x);
            Psd(x);
            if(Findroot(y)==x&&t[y].f==x&&!t[y].c[0]){
                t[x].c[1]=t[y].f=0;
                Upd(x);
            }
        }
        int Query(int x,int y){
            if(Findroot(x)!=Findroot(y)){
                return -1;
            }
            Split(x,y);
            int tmp=t[y].xs,sum=0;
            while(tmp){
                tmp-=(tmp&-tmp),++sum;
            }
            return sum;
        }
        void Change(int x,int y){
            Splay(x);
            t[x].v=y;
            Upd(x);
        }
}tr;
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++) tr.t[i].v=read(),fa[i]=i,tr.Upd(i);
    for(int i=1;i<=m;i++){
        op=read();u=read();v=read();
        if(op==1){
            int tmp=tr.Link(u,v);
            if(tmp==1){
                int Cost=(tr.t[u].v+tr.t[v].v);
                Cost>>=1;
                tr.Change(u,Cost);
                tr.Change(v,Cost);
            }
        }else if(op==2){
            int tmp=tr.Query(u,v);
            write(tmp),putchar('\n');
        }
    }
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-06-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NOIP2019模拟赛(十)06.02
    • Link
      • NOIP2019模拟赛(十)06.02
        • A. transfer
          • 题意
          • 思路
          • Code
        • B. minecraft
          • 题意
          • 思路
          • Code
        • C. rewrite
          • 题意
          • 思路
          • Code
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档