2.27模拟赛

pdf版题面

水题赛无题解

sol:可以用权值并查集搞,但感觉还是建图跑bfs比较容易

定义S[i]表示前缀和

读入a,b,c;就是S[a-1] + c=S[b],那就从a-1向b连一条c,b向a-1连一条-c

但这样有可能这张图并不联通,于是每次bfs时给节点染色,颜色不同显然to hard

询问随便处理下就可以了

/*
    S[3]-S[0]=10
    S[3]-S[2]=5
*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef int ll;
inline ll read()
{
    ll S=0;
    bool f=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        f|=(ch==‘-‘); ch=getchar();
    }
    while(isdigit(ch))
    {
        S=(S<<3)+(S<<1)+(ch-‘0‘); ch=getchar();
    }
    return (f)?(-S):(S);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar(‘-‘); x=-x;
    }
    if(x<10)
    {
        putchar(x+‘0‘); return;
    }
    write(x/10);
    putchar((x%10)+‘0‘);
    return;
}
#define W(x) write(x),putchar(‘ ‘)
#define Wl(x) write(x),putchar(‘\n‘)
const int N=100005,M=200005;
int n,m,Q,Cnt=0;
namespace Dijkstra
{
    int tot=0,Next[M],to[M],val[M],head[N];
    int Cor[N];
    inline void add(int x,int y,int z)
    {
        Next[++tot]=head[x];
        to[tot]=y;
        val[tot]=z;
        head[x]=tot;
        return;
    }
    struct Record
    {
        int Weiz,Val;
    };
    inline bool operator<(Record p,Record q)
    {
        return p.Val>q.Val;
    }
    priority_queue<Record>Queue;
    bool Arr[N];
    int Dis[N];
    inline void Run(int S,int Co)
    {
        Cor[S]=Co;
        Queue.push((Record){S,Dis[S]=0});
        int i;
        while(!Queue.empty())
        {
            Record tmp=Queue.top();
            Cor[tmp.Weiz]=Co;
            Queue.pop();
            if(Arr[tmp.Weiz]) continue;
            Arr[tmp.Weiz]=1;
            for(i=head[tmp.Weiz];i;i=Next[i])
            {
                if(Dis[to[i]]>tmp.Val+val[i])
                {
                    Dis[to[i]]=tmp.Val+val[i];
                    if(!Arr[to[i]]) Queue.push((Record){to[i],Dis[to[i]]});
                }
            }
        }
    }
    inline void Solve(int x,int y)
    {
        y++;
        if(Cor[x]!=Cor[y])
        {
            puts("Too Hard");
        }
        else
        {
            Wl(Dis[y]-Dis[x]);
        }
    }
    inline void Init()
    {
        memset(head,0,sizeof head);
        memset(Arr,0,sizeof Arr);
        memset(Dis,63,sizeof Dis);
        memset(Cor,0,sizeof Cor);
        return;
    }
}
signed main()
{
    freopen("sing.in","r",stdin);
    freopen("sing.out","w",stdout);
    R(n); R(m);
    int i;
    Dijkstra::Init();
    for(i=1;i<=m;i++)
    {
        int x=read(),y=read()+1,z=read();
        Dijkstra::add(x,y,z);
        Dijkstra::add(y,x,-z);
    }
    for(i=1;i<=n;i++) if(!Dijkstra::Arr[i])
    {
        Dijkstra::Run(i,++Cnt);
    }
    R(Q);
    for(i=1;i<=Q;i++)
    {
        int x=read(),y=read();
        Dijkstra::Solve(x,y);
    }
    return 0;
}
/*
input
4 2
1 3 10
3 3 5
2
1 2
1 4
output
5
Too Hard
*/

sol:容易发现这个n非常大,肯定不能直接上最短路

于是发现跑最短路时,真正有用的是那些中间有墙倒掉的点,对于这2*m个点

首先在有墙倒的地方建一条权值1的双向边

在对2*m个点排序,p[i]向p[i+1]连一条权值为(p[i+1]-p[i])的边

要离散。。。

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef int ll;
inline ll read()
{
    ll S=0;
    bool f=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        f|=(ch==‘-‘); ch=getchar();
    }
    while(isdigit(ch))
    {
        S=(S<<3)+(S<<1)+(ch-‘0‘); ch=getchar();
    }
    return (f)?(-S):(S);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar(‘-‘); x=-x;
    }
    if(x<10)
    {
        putchar(x+‘0‘); return;
    }
    write(x/10);
    putchar((x%10)+‘0‘);
    return;
}
#define W(x) write(x),putchar(‘ ‘)
#define Wl(x) write(x),putchar(‘\n‘)
const int N=500005,M=1000005;
int n,m;
int X[N],Y[N];
int P[N<<1];
int Pos[N<<1];
map<int,int>Map;
namespace Dijkstra
{
    int tot=0,Next[M],to[M],val[M],head[N];
    inline void add(int x,int y,int z)
    {
        Next[++tot]=head[x];
        to[tot]=y;
        val[tot]=z;
        head[x]=tot;
        return;
    }
    struct Record
    {
        int Weiz,Val;
    };
    inline bool operator<(Record p,Record q)
    {
        return p.Val>q.Val;
    }
    priority_queue<Record>Queue;
    bool Arr[N];
    int Dis[N];
    inline void Run(int S)
    {
        Queue.push((Record){S,Dis[S]=0});
        int i;
        while(!Queue.empty())
        {
            Record tmp=Queue.top();
            Queue.pop();
            if(Arr[tmp.Weiz]) continue;
            Arr[tmp.Weiz]=1;
            for(i=head[tmp.Weiz];i;i=Next[i])
            {
                if(Dis[to[i]]>tmp.Val+val[i])
                {
                    Dis[to[i]]=tmp.Val+val[i];
                    if(!Arr[to[i]]) Queue.push((Record){to[i],Dis[to[i]]});
                }
            }
        }
    }
    inline void Init()
    {
        memset(head,0,sizeof head);
        memset(Arr,0,sizeof Arr);
        memset(Dis,63,sizeof Dis);
        return;
    }
}
#define Dj Dijkstra
signed main()
{
    freopen("lh.in","r",stdin);
    freopen("lh.out","w",stdout);
    R(n); R(m);
    int i;
    Dj::Init();
    for(i=1;i<=m;i++)
    {
        X[i]=read();
        Y[i]=read();
        if(!Map[X[i]])
        {
            P[Map[X[i]]=++*P]=X[i];
        }
        if(!Map[Y[i]])
        {
            P[Map[Y[i]]=++*P]=Y[i];
        }
        Dj::add(Map[X[i]],Map[Y[i]],1);
        Dj::add(Map[Y[i]],Map[X[i]],1);
    }
    if(!Map[1])
    {
        P[Map[1]=++*P]=1;
    }
    if(!Map[n])
    {
        P[Map[n]=++*P]=n;
    }
    sort(P+1,P+*P+1);
    for(i=1;i<*P;i++)
    {
        Dj::add(Map[P[i]],Map[P[i+1]],P[i+1]-P[i]);
        Dj::add(Map[P[i+1]],Map[P[i]],P[i+1]-P[i]);
    }
    Dj::Run(Map[1]);
    Wl(Dj::Dis[Map[n]]);
    return 0;
}
/*
input
31
9
4 15
10 25
13 30
1 6
2 9
6 19
9 24
10 27
1 4
output
6
Too Hard
*/

sol:看上去很厉害其实只是MST的板子罢了,一堆描述只是在故弄玄虚,就是说没有环。

Prim随便水

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll S=0;
    bool f=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        f|=(ch==‘-‘); ch=getchar();
    }
    while(isdigit(ch))
    {
        S=(S<<3)+(S<<1)+(ch-‘0‘); ch=getchar();
    }
    return (f)?(-S):(S);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar(‘-‘); x=-x;
    }
    if(x<10)
    {
        putchar(x+‘0‘); return;
    }
    write(x/10);
    putchar((x%10)+‘0‘);
    return;
}
#define W(x) write(x),putchar(‘ ‘)
#define Wl(x) write(x),putchar(‘\n‘)
const int N=5005;
int n;
struct Point
{
    int x,y;
}P[N];
double DD[N];
int Father[N];
bool Vis[N];
inline double Calc(int i,int j)
{
    double ix=P[i].x,iy=P[i].y,jx=P[j].x,jy=P[j].y;
    return sqrt((ix-jx)*(ix-jx)+(iy-jy)*(iy-jy));
}
int main()
{
    freopen("torture.in","r",stdin);
    freopen("torture.out","w",stdout);
    int i,j;
    R(n);
    for(i=1;i<=n;i++)
    {
        Father[i]=i;
        R(P[i].x);
        R(P[i].y);
    }
    int step;
    double ans=0;
    for(i=2;i<=n;i++) DD[i]=1e15;
    DD[1]=0;
    for(step=1;step<n;step++)
    {
        int u=-1;
        for(i=1;i<=n;i++) if((!Vis[i])&&(u==-1||DD[i]<DD[u])) u=i;
        Vis[u]=1;
        for(i=1;i<=n;i++) if((!Vis[i])&&(DD[i]>Calc(u,i)))
        {
            DD[i]=Calc(u,i);
        }
    }
    for(i=1;i<=n;i++) ans+=DD[i];
    printf("%.2lf\n",ans);
    return 0;
}
/*
input
4
0 0
1 2
-1 2
0 4
output
6.47
*/

updata:首先对于题面有一处修正,两个点之间的距离是min(|Xa-Xb|,|Ya-Yb|,|Za-Zb|),题面中少了个min,而且也不是曼哈顿距离

sol:对三维分别排序,得到3*(n-1)条边,Kruskal直接上

Xjb证明:只有一维时,显然排好序后第i个向i+1连边最优,

当有三维时,Kruskal保证当前边权是没选过的中最小的,相当于已经在3维中去过min了,于是可以直接做了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll S=0;
    bool f=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        f|=(ch==‘-‘); ch=getchar();
    }
    while(isdigit(ch))
    {
        S=(S<<3)+(S<<1)+(ch-‘0‘); ch=getchar();
    }
    return (f)?(-S):(S);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar(‘-‘); x=-x;
    }
    if(x<10)
    {
        putchar(x+‘0‘); return;
    }
    write(x/10);
    putchar((x%10)+‘0‘);
    return;
}
#define W(x) write(x),putchar(‘ ‘)
#define Wl(x) write(x),putchar(‘\n‘)
const int N=100005;
int n;
int Father[N];
struct Point
{
    int Weiz,Id;
}X[N],Y[N],Z[N];
inline bool Point_cmp(Point a,Point b)
{
    return a.Weiz<b.Weiz;
}
int cnt=0;
struct Edge
{
    int U,V,Bianquan;
}E[N*3];
inline bool Edge_cmp(Edge a,Edge b)
{
    return a.Bianquan<b.Bianquan;
}
inline int Get_Father(int x)
{
    return (Father[x]==x)?(x):(Father[x]=Get_Father(Father[x]));
}
int main()
{
    freopen("time.in","r",stdin);
    freopen("time.out","w",stdout);
    int i;
    R(n);
    for(i=1;i<=n;i++)
    {
        X[i]=(Point){read(),i};
        Y[i]=(Point){read(),i};
        Z[i]=(Point){read(),i};
    }
    sort(X+1,X+n+1,Point_cmp);
    for(i=1;i<n;i++)
    {
        E[++cnt]=(Edge){X[i].Id,X[i+1].Id,X[i+1].Weiz-X[i].Weiz};
    }
    sort(Y+1,Y+n+1,Point_cmp);
    for(i=1;i<n;i++)
    {
        E[++cnt]=(Edge){Y[i].Id,Y[i+1].Id,Y[i+1].Weiz-Y[i].Weiz};
    }
    sort(Z+1,Z+n+1,Point_cmp);
    for(i=1;i<n;i++)
    {
        E[++cnt]=(Edge){Z[i].Id,Z[i+1].Id,Z[i+1].Weiz-Z[i].Weiz};
    }
    sort(E+1,E+cnt+1,Edge_cmp);
    for(i=1;i<=n;i++)
    {
        Father[i]=i;
    }
    ll ans=0;
    int Bians=0;
    for(i=1;i<=cnt;i++)
    {
        int u=E[i].U,v=E[i].V;
        int uu=Get_Father(u),vv=Get_Father(v);
        if(uu==vv) continue;
        ans+=1ll*E[i].Bianquan;
        Father[uu]=vv;
        if(++Bians==n-1) break;
    }
    Wl(ans);
    return 0;
}
/*
input
5
11 -15 -15
14 -5 -15
-1 -1 -5
10 -4 -1
19 -4 19
output
4
*/

原文地址:https://www.cnblogs.com/gaojunonly1/p/10453070.html

时间: 2024-10-03 05:31:01

2.27模拟赛的相关文章

11.27 模拟赛

并没有人做的模拟赛... 出题人hx,,, T1:就是上一道矩阵乘法 数学题 T2: 一个数列中 一个区间满足,存在一个k(L <= k <= R),并且对于任意的i (L <= i <= R),ai都能被ak整除 这样的一个特殊区间 [L, R]价值为R - L 想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢 这些区间又分别是哪些呢 输出每个区间的L 思路: 用两个ST表分别求一段区间的gcd和最小值 然后可以二分答案 check的时候枚举左端点,判断在这段区间

10.27 模拟赛

这一次终极被吊打 甚至没进前十 T2 最后改错 T3 没写正解 T1 elim 题目大意: n 行 m 列的游戏棋盘,一行或一列上有连续 三个或更多的相同颜色的棋子时,这些棋子都被消除 当有多处可以被消除时,这些地方的棋子将同时被消除 求消除后的棋盘 思路: sb模拟 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cm

2017 9 27 模拟赛T1

题意简述: 求1-n中所有数的k次方的和,答案对1234567891取模. 样例输入格式: 一行,两个整数n,k 样例输出格式: 一个整数,即所求的和. 数据范围:n<10^9,k<100 这道题n非常大,即使是O(n)的算法也不能承受,但是此题的k却非常小,这也就提醒由k入手. 首先预处理前k+1个数的k次方的和,如果n<=k+1的话其实就可以直接输出a[0][n]了,不过我觉得出题人不会出这样的数据. 为什么是k+1个数呢?这是为了能处理一些差分的问题. 然后不断地计算每一行的差分,

2017 9 27 模拟赛 T2

原题题意:给出一个集合S,现满足以下关系: 实际题意:求32的n次方(这...)

【BZOJ】【2741】【FOTILE模拟赛】L

可持久化Trie+分块 神题……Orz zyf & lyd 首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问[某个区间中最大的区间异或和]改变成[某个区间中 max(两个数的异或和)] 要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了:然而我们并不能. 一个常见的折中方案:分块! 这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值. 我们不预处理所有的左端点,我

10.30 NFLS-NOIP模拟赛 解题报告

总结:今天去了NOIP模拟赛,其实是几道USACO的经典的题目,第一题和最后一题都有思路,第二题是我一开始写了个spfa,写了一半中途发现应该是矩阵乘法,然后没做完,然后就没有然后了!第二题的暴力都没码QAQ 现在我来写解题报告了,有点饿了QAQ.. 第一题 题目 1: 架设电话线 [Jeffrey Wang, 2007] 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务,于 是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线.新的电话线架设 在已有的N(2 <=

【题解】PAT团体程序设计天梯赛 - 模拟赛

由于本人愚笨,最后一题实在无力AC,于是只有前14题的题解Orz 总的来说,这次模拟赛的题目不算难,前14题基本上一眼就有思路,但是某些题写起来确实不太容易,编码复杂度有点高~ L1-1 N个数求和 设计一个分数类,重载加法运算符,注意要约分,用欧几里得算法求个最大公约数即可. 1 #include <cstdio> 2 3 long long abs(long long x) 4 { 5 return x < 0 ? -x : x; 6 } 7 8 long long gcd(long

[GRYZ]寒假模拟赛

写在前面 这是首次广饶一中的OIERS自编自导,自出自做(zuo)的模拟赛. 鉴于水平气压比较低,机(wei)智(suo)的WMY/XYD/HYXZC就上网FQ下海找了不少水(fei)题,经过他们优(le)美(se)的文字加工后,有故事有题目有人物有奸情的模拟赛正式呈上. 我是正文 题目名 GRYZ娱乐时刻 GRYZ追击时刻 GRYZ就餐时刻 源文件 hyxzc.cpp/c/pas clikar.cpp/c/pas eat.cpp/c/pas 输入文件 hyxzc.in clikar.in ea

[铁一中OI模拟赛]2017.8.19 Day1

T1 小Z的情书 题目链接 思考: 题目主要难度在于旋转后的位置如何,在手写了样例之后不难发现规律. #include <cstdio> #include <cstring> #define up(a,b,c) for(register int c=a;c<=b;++c) #define down(a,b,c) for(register int c=a;c>=b;--c) const int Maxn=1005; int n; bool Map[Maxn][Maxn],