Noip模拟题解题报告

Pro

题目链接

Sco

预计得分: 100+100+=200 100 + 100 + ? = 200

实际得分: 100+70+=170 100 + 70 + ? = 170

PS:第三题好麻烦,打了好几节课

Sol

铺瓷砖

很简单的分数求 lcm l c m 的问题

最后答案注意约分,还要特判分母为 1 1 的情况

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

int T , A , B , C , D;
long long T1 , T2 , T3;

long long gcd(long long x , long long y) {
    while(y) {
        int t = x % y;
        x = y;
        y = t;
    }
    return x;
}

long long lcm(long long x , long long y) {
    return x * y / gcd(x , y);
}

int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d%d",&A,&B,&C,&D);
        T1 = lcm(B , D);
        T2 = lcm((T1/B)*A , (T1/D)*C);
        T3 = gcd(T1 , T2);
        if(T1/T3 == 1)
            printf("%lld\n",T2/T3);
        else
            printf("%lld/%lld\n",T2/T3,T1/T3);      
    }
    return 0;
}

小Y的问题

第一次读完题没看到第一问

第一问很简单,就是一个组合数问题:

对于每一个结点,维护出与该结点相连的结点数,存到ind

第一问答案即为: ni=1C2ind[i]1 ∑ i = 1 n C i n d [ i ] − 1 2 , 其中 ind[i]>=3 i n d [ i ] >= 3

化简一下式子就变成了: ni=1(ind[i]1)(ind[i]2)2 ∑ i = 1 n ( i n d [ i ] − 1 ) ( i n d [ i ] − 2 ) 2

第二问呢,也是比较好想的:

对于每一个点维护与该点相连的边权的前四大

这样就可以枚举每一个点,枚举的这个点作为 Y Y 字形的中间的那个点

很明显,如果满足条件,一定是所连的边大于等于3,与第一问中一样,就可以一起做的

对于这个点再枚举Y字形最下面的那个点

第二问答案就是以 Y Y 字形中间的那个点开始的前两大加上以最下面点的第一大

当前要除去已经使用过的点

#include<iostream>
#include<cstdio>
using namespace std;

const int L = 200005;
struct Node {
    int to , next;
    long long len;
};
Node e[2*L];
struct Tree {
    int num;
    long long len;
};
Tree maxa[L][5];
int n , head[L] , tot , ind[L];
long long ans1 , ans2;
inline long long mymax(long long a , long long b) { return a>b?a:b; }

void add(int x , int y , long long z) {
    tot++;
    e[tot].to = y;
    e[tot].next = head[x];
    e[tot].len = z;
    head[x] = tot;
}

void update(int x , int y , long long z) {
    for(int i=1; i<=4; i++)
        if(z >= maxa[x][i].len) {
            for(int j=4; j>=i+1; j--)
                maxa[x][j] = maxa[x][j-1];
            maxa[x][i].len = z;
            maxa[x][i].num = y;
            break;
        }
    for(int i=1; i<=4; i++)
        if(z >= maxa[y][i].len) {
            for(int j=4; j>=i+1; j--)
                maxa[y][j] = maxa[y][j-1];
            maxa[y][i].len = z;
            maxa[y][i].num = x;
            break;
        }
}

long long find1(int x , int y) {
    long long res = 0 , cnt = 0;
    for(int i=1; i<=4; i++)
        if(maxa[x][i].num != y) {
            cnt++;
            res += maxa[x][i].len;
            if(cnt == 2)
                return res;
        }
}

long long find2(int x , int y) {
    if(maxa[x][1].num == y)
        return maxa[x][2].len;
    return maxa[x][1].len;
}

int main() {
    freopen("question.in","r",stdin);
    freopen("question.out","w",stdout);
    scanf("%d",&n);
    for(int i=1; i<n; i++) {
        int x , y;
        long long z;
        scanf("%d%d%lld",&x,&y,&z);
        ind[x]++;
        ind[y]++;
        add(x , y , z);
        add(y , x , z);
        update(x , y , z);
    }   
    for(int i=1; i<=n; i++) {
        if(ind[i] < 3)
            continue;
        long long cnt = (long long)(ind[i]-1)*(ind[i]-2)/2;
        for(int j=head[i]; j; j=e[j].next)
            if(ind[e[j].to] > 1) {
                ans1 += (ind[e[j].to]-1)*cnt;
                ans2 = mymax(ans2 , find1(i , e[j].to) + e[j].len + find2(e[j].to , i));
            }
    }
    printf("%lld\n%lld",ans1,ans2);
    return 0;
}

水管工的难题

最毒瘤的一道题,尽管只是个搜索……

用曼哈顿距离来进行最优性剪枝

其实不必把每一个方向都求出来

只需要xyz加一或者减一,然后等会搜索的时候乘二或者乘三就行

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
using namespace std;

long stime,ttime;
struct Node {
    int x , y , z , opt;
    bool operator == (const Node &a) const {
        return (a.x == x && a.y == y && a.z == z && a.opt == opt);
    }
};
Node S , T;
const int dx[] = { 1, -1, 0, 0, 0, 0 }, dy[] = { 0, 0, 1, -1, 0, 0 }, dz[] = { 0, 0, 0, 0, 1, -1 };
int X , Y , Z , n , vis[25][25][25] , ans = 13 , za[25][25][25] , sdir , tdir;
char c;
inline int myabs(int a) { return a<0?(-a):a; }
inline int mymin(int a , int b) { return a<b?a:b; }

int jud(int x , int y , int z) {
    if (x >= 1 && x <= X && y >= 1 && y <= Y && z >= 1 && z <= Z && !vis[x][y][z] && !za[x][y][z])
        return 1;
    return 0;
}

void dfs(Node x , int cnt) {
    int dis = myabs(T.x-x.x) + myabs(T.y-x.y) + myabs(T.z-x.z);
    if(cnt + dis/4 >= ans || cnt + dis/4 > 12)
        return ;
    if(x == T) {
        ans = mymin(ans , cnt);
        return ;
    }
    if(jud(x.x+dx[x.opt] , x.y+dy[x.opt] , x.z+dz[x.opt]) && jud(x.x+2*dx[x.opt] , x.y+2*dy[x.opt] , x.z+2*dz[x.opt])) {
        vis[x.x+dx[x.opt]][x.y+dy[x.opt]][x.z+dz[x.opt]] = vis[x.x+2*dx[x.opt]][x.y+2*dy[x.opt]][x.z+2*dz[x.opt]] = 1;
        int nx = x.x+2*dx[x.opt] , ny = x.y+2*dy[x.opt] , nz = x.z+2*dz[x.opt];
        for(int i=0; i<6; i++) {
            if(i/2 != x.opt/2) {
                if(jud(nx+dx[i] , ny+dy[i] , nz+dz[i]) && jud(nx+2*dx[i] , ny+2*dy[i] , nz+2*dz[i])) {
                    vis[nx+dx[i]][ny+dy[i]][nz+dz[i]] = vis[nx+2*dx[i]][ny+2*dy[i]][nz+2*dz[i]] = 1;
                    Node t;t.x= nx+2*dx[i] , t.y = ny+2*dy[i] , t.z = nz+2*dz[i] ,  t.opt = i;              
                    dfs(t , cnt+1);
                    vis[nx+dx[i]][ny+dy[i]][nz+dz[i]] = vis[nx+2*dx[i]][ny+2*dy[i]][nz+2*dz[i]] = 0;
                }
            }
        }
        if(jud(x.x+3*dx[x.opt] , x.y+3*dy[x.opt] , x.z+3*dz[x.opt])) {
            vis[x.x+3*dx[x.opt]][x.y+3*dy[x.opt]][x.z+3*dz[x.opt]] = 1;
            int nx = x.x+3*dx[x.opt] , ny = x.y+3*dy[x.opt] , nz = x.z+3*dz[x.opt]; 
            for(int i=0; i<6; i++) {
                if(i/2 != x.opt/2) {
                    if(jud(nx+dx[i] , ny+dy[i] , nz+dz[i])) {
                        vis[nx+dx[i]][ny+dy[i]][nz+dz[i]] = 1;
                        Node t;t.x= nx+dx[i] , t.y = ny+dy[i] , t.z = nz+dz[i] ,  t.opt = i;
                        dfs(t , cnt+1);
                        vis[nx+dx[i]][ny+dy[i]][nz+dz[i]] = 0;
                    }
                }
            }
            vis[x.x+3*dx[x.opt]][x.y+3*dy[x.opt]][x.z+3*dz[x.opt]] = 0; 
        }
        vis[x.x+dx[x.opt]][x.y+dy[x.opt]][x.z+dz[x.opt]] = 0;
        vis[x.x+2*dx[x.opt]][x.y+2*dy[x.opt]][x.z+2*dz[x.opt]] = 0;
    }
}

int main() {
    freopen("plumber.in","r",stdin);
    freopen("plumber.out","w",stdout);
    stime = clock();
    scanf("%d%d%d%d",&X,&Y,&Z,&n);
    scanf("%d%d%d",&S.x,&S.y,&S.z);
    cin>>c;
    sdir = (c - 'x') * 2;
    if (c == 'x')
        sdir += (S.x == X);
    if (c == 'y')
        sdir += (S.y == Y);
    if (c == 'z')
        sdir += (S.z == Z);
    S.x -= dx[sdir];
    S.y -= dy[sdir];
    S.z -= dz[sdir];
    S.opt = sdir;
    scanf("%d%d%d",&T.x,&T.y,&T.z);
    cin>>c;
    tdir = (c - 'x') * 2;   
    if (c == 'x')
        tdir += (T.x == 1);
    if (c == 'y')
        tdir += (T.y == 1);
    if (c == 'z')
        tdir += (T.z == 1);
    T.opt = tdir;
    for(int i=1; i<=n; i++) {
        int x , y , z;
        scanf("%d%d%d",&x,&y,&z);
        za[x][y][z] = 1;
    }
    dfs(S , 0);
    if(ans == 13)
        printf("impossible\n");
    else
        printf("%d\n",ans);
    ttime = clock();
//  cout<<"AC time:"<<ttime-stime<<"ms";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOIP(全国青少年信息学奥林匹克竞赛)是中国国内最高水平的信息学竞赛之一,是计算机领域的重要赛事。针对NOIP模拟题,通常是为了帮助参赛者熟悉比赛形式和题型,提供足够的训练机会。 数据下载是NOIP比赛中的一个重要环节,因为参赛者需要根据提供的数据集进行程序开发和测试。数据下载一般通过网络进行,参赛者需要在指定的时间段内下载数据集到自己的计算机上。 在进行NOIP模拟题数据下载时,我们可以按照以下步骤进行操作: 1. 确认下载链接:NOIP官方会提供下载数据集的链接或者FTP地址,参赛者需要确认链接是否可用和正确。 2. 选择下载工具:根据自己的需求,参赛者可以选择合适的下载工具进行操作。常见的下载工具有浏览器内置下载工具、迅雷、IDM等,可以根据个人的习惯和需求选择合适的下载工具。 3. 打开下载工具:根据所选择的下载工具类型,打开对应的软件,进入下载界面。 4. 输入下载链接:将NOIP提供的数据集下载链接复制粘贴到下载工具的链接输入框中,点击确定或开始进行下载。 5. 等待下载完成:根据数据集的大小和网络速度不同,下载时间会有所变化。参赛者需要耐心等待下载完成,确保数据集完整地保存到自己的计算机上。 6. 验证数据完整性:下载完成后,参赛者需要验证数据集的完整性,确保所有文件都成功地保存到指定位置。可以进行文件大小的比对或者逐个文件的校验来检查数据完整性。 通过以上步骤,参赛者可以成功地进行NOIP模拟题数据的下载。在实际比赛中,一个高效的数据下载过程可以提高参赛者的准备时间和竞争力,确保能够充分利用所提供的数据集进行开发和测试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值