Logo __vector__ 的博客

博客

How to AK ABC240

...
__vector__
2025-12-01 12:55:44

本文章由 WyOJ Shojo 从洛谷专栏拉取,原发布时间为 2022-02-26 19:02:04

A - Edge Checker

题目大意:

1 到 10 按顺序组成一个环(1 和 10 首尾连接)
给定两个数,问是否相邻。

题目分析:

签到题不需要分析。

$\color{green}\text{AC代码:}$

#include <bits\/stdc++.h>
using namespace std;
int main()
{
    int a,b;
    cin>>a>>b;
    if((a==1&&b==10)||(a==10&&b==1))
    {
        cout<<"Yes";
        return 0;
    }
    if(abs(a-b)<=1)cout<<"Yes";
    else cout<<"No";
    #ifndef ONLINE_JUDGE
    system("pause");
    #endif
    return 0;
}

B - Count Distinct Integers

题目大意:

给定一个长度为 $n$ 的数组,问有多少不同的数字。

题目分析:

签到题不需要分析。

$\color{green}\text{AC代码:}$

#include <bits\/stdc++.h>
using namespace std;
const int maxn=1005;
int a[maxn];
map<int,int> im;
int main()
{
    int n;
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        if(!im[a[i]])ans++;
        im[a[i]]=1;
    }
    cout<<ans;
    #ifndef ONLINE_JUDGE
    system("pause");
    #endif
    return 0;
}

C - Jumping Takahashi

题目大意:

某人的起始坐标为0(向左为负向右为正)。给定两个长度为 $N$ 的数组,$a$ 和 $b$,这个人第 $i$ 次跳可以向右移动 $ai$ 个单位或 $bi$ 个单位。问经过 $n$ 次跳跃之后是否能到达点 $X$(必须跳 $N$ 次)。
$1 \le N \le 100$

题目分析:

由于本人太菜,只会 $O(2^n)$ 的爆搜,所以就来说一下怎么写爆搜过题,正确算法等我看了官方题解之后再放上来。
首先,朴素的爆搜肯定大家都会写,但是 $O(2^n)$ 的复杂度就算评测机能 $n^2$ 过百万也不行。所以要加剪枝,现在来讲一下怎么写剪枝。
剪枝一:如果当前搜到的数总和超过了 $X$ ,那么返回。
剪枝二:如果当前搜到的数字总和,后面即使每次都选最大的数,总和仍然比 $X$ 小,那么返回。
剪枝三:如果当前搜到的数字总和,后面即使每次都选最小的数,总和仍然比 $X$ 大,那么返回。 来看一看效果:

可见剪枝效果显著,但是仍然无法通过此题。
怎么办?
为了 AC,我加了一个错误的剪枝:
如果递归超过 2000万次还没有搜到结果,那么有解的可能很小(随机数据下),那么直接输出 No
但是这个是错的,我自己就能 hack 掉。但是 At 的数据太水了所以过了。
正确做法我看完官方题解再放上来。
(还好不是 CF 赛制)

$\color{red}\text{错误}$ $\color{blue}\text{但是}$$\color{green}\text{AC的代码:}$

#include <bits\/stdc++.h>
using namespace std;
const int maxn=105;
int a[maxn];
int b[maxn];
int qzh[maxn];
int qzh2[maxn];
int n,x;
int cnt=0;
bool dfs(int i,int col)
{
    if(++cnt>=20000000)return 0;
 \/\/   cout<<"i: "<<i<<" col"<<col<<endl;
    if(col==x&&i==n+1)return 1;
    if(i==n+1)return 0;
    if(col>x)return 0;
\/\/    cout<<"qzh"<< qzh[n]-qzh[i]<<endl;
\/\/    cout<<"qzh"<< qzh2[n]-qzh2[i]<<endl;
\/\/cout<<col+(qzh[n]-qzh[i])<<endl;
\/\/cout<<col+(qzh2[n]-qzh2[i])<<endl;
    if(col+(qzh[n]-qzh[i])>x)return 0;
    if(col+(qzh2[n]-qzh2[i])<x)return 0;
 \/\/   cout<<"i: "<<i<<endl;
    if(dfs(i+1,col+a[i+1]))return 1;
    if(dfs(i+1,col+b[i+1]))return 1;
    return 0;
}

int main()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i]>>b[i];
        qzh[i]=qzh[i-1]+min(a[i],b[i]);
        qzh2[i]=qzh2[i-1]+max(a[i],b[i]);
    }
    if(dfs(1,a[1])||dfs(1,b[1]))cout<<"Yes";
    else cout<<"No";
    #ifndef ONLINE_JUDGE
    system("pause");
    #endif
    return 0;
}

D - Strange Balls

题目大意:

有 $n$ 个球,每个球都有一个数值 $a_i$。
这些球按照顺序从第 $1$ 个到第 $n$ 个依次放入一个瓶子里。放入一个球后如果出现了有连续 $a_i$ 个球的数值为 $a_i$。那么这连续 $a_i$ 个球都会消失。
问每放入一个球之后瓶子里有多少球。

题目分析:

可以创建一个栈 $sta$,对于每一块连续的球都用一个节点 $sta_i$ 表示。对于每个节点 $sta_i$ 存储当前块有多少个球,以及当前块存的球的数值。
插入一个球之后,如果这个球数值与栈顶节点不一样,那么新建一个节点插入栈顶。如果一样,那么栈顶节点 $sta_{top}$ 存储的球数 $+1$,如果发现 $sta_{top}$ 存储的球数 $ = sta_{top}$的数值,那么删除 $sta_top$ 即可。

$\color{green}\text{AC代码:}$

#include <bits\/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n;
int a[maxn];
int top;
struct Sta
{
    int size;
    int val;
}sta[maxn];
int ans=0;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        if(a[i]!=sta[top].val)
        {
            sta[++top]={1,a[i]};
            ans++;
            printf("%d\n",ans);
        }
        else
        {
            sta[top].size++;
            ans++;
            if(sta[top].size==a[i])
            {
                ans-=sta[top].size;
                top--;
            }
            printf("%d\n",ans);
        }
    }
    #ifndef ONLINE_JUDGE
    system("pause");
    #endif
    return 0;
}

E - Ranges on Tree

题目大意:

$[l,r] = l,l+1,l+2.......r-1,r$
给定一棵树。树上的每个点都有两个值 $(l_i,r_i)$。
设第 $i$ 个节点的子树为集合 $s_i$。
每个点的值应满足一下要求:
一、如果点 $a$ 是点 $b$ 的子节点,那么 $[l_a,r_a]$ 应包含在 $[l_b,r_b]$ 中。
二、如果点 $a$ 和点 $b$ 是独立的两棵树,那么 $[l_a,r_a]$ 应和 $[l_b,r_b]$ 无交集。
对每个节点安排它的 $(l,r)$,使得 $max(l_1,l_2,l_3......l_n,r_1,r_2,r_3......r_n)$ 最小。

题目分析

大力 dfs!
首先确定叶子节点的值,然后,每个节点的 father 节点的值也就是 $(min({{s_i}_j}.l),max({{s_i}_j}.r))$
注: ${{s_i}_j}$ 代表 $s_i$ 的第 $j$ 个元素。
如何确定叶子结点的值呢? 定义一个变量 $sum$ ,当前点每搜到一个子节点点就 sum++。(为了避免误差,每个点搜到第一个子节点时不用增加 $sum$)
对于搜到的每个点首先把这个点的 $l$ 设为 $sum$,从这个点搜完它的所有子节点之后,再把它的 $r$ 设为 $sum$。
这样就完成了。

$\color{green}\text{AC代码:}$

#include <bits\/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int head[maxn<<1];
struct EDGE
{
    int to,nxt;
}edge[maxn<<1];
int tot;
inline void add(int u,int to)
{
    edge[++tot].to=to;
    edge[tot].nxt=head[u];
    head[u]=tot;
}
int n;
int rd[maxn];\/\/存储入度
struct Val
{
    int l,r;
}val[maxn];\/\/存储每个点的取值范围
int dbg;
bool vis[maxn];
int sum=1;
void dfs(int u)
{
    val[u].l=sum;
    vis[u]=1;
    bool flag=0;
    \/\/因为如果当前点有子树的话
    \/\/统计答案会多统计1
    \/\/在此需要标明以来
    \/\/减去这个误差
    for(int i=head[u];i;i=edge[i].nxt)
    {
        int to=edge[i].to;
        if(vis[to])continue;
        if(flag)sum++;
        flag|=1;
        dfs(to);
    }
    val[u].r=sum;
}
int main()
{
    scanf("%d",&n);
    int ut,vt;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&ut,&vt);
        add(ut,vt);
        add(vt,ut);
        rd[ut]++;
        rd[vt]++;
    }
    dfs(1);
    for(int i=1;i<=n;i++)
    {
        printf("%d %d\n",val[i].l,val[i].r);
    }
    #ifndef ONLINE_JUDGE
    system("pause");
    #endif
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。