8 12 考试总结

8 12 考试总结

难度分布不是很合理? 果然只是我太菜了

T1

原题: [ARC164B] Switching Travel

观察题意:可以发现是找一条黑白相间,两端颜色一致的链拼起来的环。

讲真,当时想的是直接爆搜的,但在设计时遇到了一些问题,导致没写出来。

正解是并查集判环。

若一条边连接的两点颜色不同,则其链接的两点加入同一并查集中,表示为一条链。

最后遍历一遍边,查找是否有相邻的点颜色相同且其在同一并查集中。

AC code:

#include <bits/stdc++.h>
#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ll long long
using namespace std;
const int maxn = 2e5+10;
int n,m,fa[maxn],a[maxn];
struct node{
    int u,v;
}e[maxn];
bool cmp;
int find(int x){
    if(fa[x]==x) return fa[x];
    return fa[x]=find(fa[x]);
}
void join(int x,int y){
    fa[find(x)]=find(y);
}
int u,v;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    seq(i,1,m){
        cin>>u>>v;
        e[i]=(node){u,v};
    }
    seq(i,1,n){
        cin>>a[i];
        fa[i]=i;    //并查集初始化
    } 
    seq(i,1,m)
        if(a[e[i].u]!=a[e[i].v]) join(e[i].u,e[i].v);      
    //若边连接的两边颜色不同,则表示此边是可走的
    seq(i,1,m){
        if(a[e[i].u]==a[e[i].v]&&find(e[i].u)==find(e[i].v)) 
            //查找相邻的,且处于同意并查集的点,有即yes 
            cmp=1; 
    }
    if(cmp){
        cout<<"Yes";
    }
    else{
        cout<<"No";
    }
    return 0;
}

T2

P1198 最大数

一眼鉴定为线段树。主要是我做过

对标朴素线段树,此题的线段树较为特殊,由于其动态的加入点,于是乎我们省去了建树操作。但线段树复杂的结构导致其维护时不是简单的 \(tree[++tot]=x\) 就可以解决的。

则我们假设每个操作都是加点,则此线段树序列的极限长度为 \(m\) ,如是便可进行操作。

维护一个 \(cnt\) 表示当前序列的末尾。用普通线段树的 单点修改+区间查询 即可。

AC code:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll inf=-114514;
ll m,cnt;
char op[2];
ll data[800005],x,t,p;
ll max(ll a,ll b)
{
    return a>b?a:b;
}
void add(ll s,ll k,ll o,ll l,ll r)
{
    if(l==r)
    {
        data[o]=k;
        return;
    }
    ll mid=(l+r)>>1;
    if(mid>=s) add(s,k,o<<1,l,mid);
    if(mid<s) add(s,k,o<<1|1,mid+1,r);
       data[o]=max(data[o<<1],data[o<<1|1])%p;
}
ll ask(ll lc,ll rr,ll o,ll l,ll r)
{
    if(lc<=l&&rr>=r) return data[o];
    ll mid=(l+r)>>1;
    ll a=inf,b=inf;
    if(mid>=lc) a=ask(lc,rr,o<<1,l,mid);
    if(mid<rr) b=ask(lc,rr,o<<1|1,mid+1,r);
    return max(a,b);
}
signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>m>>p;
    for(ll i=0;i<m;i++)
    {
        cin>>op>>x;
        if(op[0]=='A')
        {
            add(cnt+1,(x+t)%p,1,1,m);
            cnt++;
         }
         if(op[0]=='Q')
        {
            if(x==0) t=0;
            else t=ask(cnt-x+1,cnt,1,1,m)%p;
            cout<<t<<endl;
        }
    }
    return 0;
}

T3

P1440 求m区间内的最小值

其实读完题就可以发现,这是单调队列板子( P1886 滑动窗口 /【模板】单调队列 ) ,但考试时忘了单调队列怎么写。所以说,这题也用的线段树。 (讲真 \(2^{22}\) 的数据范围竟然不会爆空间,有点惊讶)

既然是线段树,那么思路十分好想。简单的区间 \(RMQ\) 问题。建完树后, \([1,n]\) 扫一遍,输出query(i-m,i-1) 即可。

注:虽然题干上说数据范围为 \(2e6\) 但线段树开 \(2e6 \times 4\)\(WA\) #2,#7。应开到 \(2^{22}\) ,才不会越界。以及,实测不用快读也能 \(AC\)

AC code:

#include<bits/stdc++.h>
#define ll long long
#define seq(q,w,e) for(int q=w;q<=e;q++)
using namespace std;
const int maxn=4194304;
ll tree[maxn<<2];
ll ls(ll p){return p<<1;}
ll rs(ll p){return (p<<1)|1;}
void push_up(ll p){
	tree[p]=min(tree[ls(p)],tree[rs(p)]);
}
void build_tree(ll p,ll pl,ll pr){
	if(pl==pr){
        cin>>tree[p];
		return;
	}
	ll mid=(pl+pr)>>1;
	build_tree(ls(p),pl,mid);
	build_tree(rs(p),mid+1,pr);
	push_up(p);
}
ll query(ll l,ll r,ll p,ll pl,ll pr){
	if(l>r) return 0;
	if(l<=pl&&r>=pr) return tree[p];
	ll mid=(pl+pr)>>1;
	ll ans=maxn;
	if(l<=mid) ans=min(ans,query(l,r,ls(p),pl,mid));
	if(r>mid) ans=min(ans,query(l,r,rs(p),mid+1,pr));
	return ans;
}
ll n,m;
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m;
	build_tree(1,1,n);
	seq(i,1,n){
        int l=i-m,r=i-1;
        if(l<=0) l=1;
        if(l>r){
            cout<<"0"<<"\n";
            continue;
        }
        cout<<query(l,r,1,1,n)<<"\n";
	}
	return 0;
}

T4

P7076 动物园

考试时盯着这题看了二十分钟,完全没思路,成功爆0。

直接来看正解吧,由于其保证 \(q_i\) 互不相同,于是饲料并不重要。先计算已有的动物编号,哪些位上至少存在一次,用 \(|\) 操作。

对于每个操作,若 \(p_i\) 存在,则此种饲料一定存在。反之一定没有,即这一位一定不为1。

除去一定不为1的位,剩下 \(t\) 个位可能为1,那总动物数可以达到 \(2^t\) ,减去已有的 \(n\) 种,所以答案是 \(2^t-n\)

注:全程要用 unsigned long long ,当 \(t=64\) 时,会爆 ull ,所以特判,输出 \(18446744073709551616\) 即可。

AC code:

#include <bits/stdc++.h>
#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ull unsigned long long
using namespace std;
const int maxn = 1e5+10;
int n,m,c,k;
ull sum,b;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m>>c>>k;
    seq(i,1,n){
        ull x;
        cin>>x;
        sum|=x;
    }
    while(m--){
        int p,op;
        cin>>p>>op;
        if((sum>>p&1)==0) b|=1ull<<p;
    }
    ull ans=1;
    for (int i=0;i<k;i++){
        if((b>>i&1)==0) ans<<=1;
    }
    if(ans==0&&n==0){
        cout<<"18446744073709551616";
        return 0;
    }
    ans-=n;
    cout<<ans<<"\n";
    return 0;
}
posted @ 2024-08-13 15:18  adsd45666  阅读(5)  评论(0编辑  收藏  举报