首页 > 其他分享 >AtCoder Beginner Contest 368(ABC368)

AtCoder Beginner Contest 368(ABC368)

时间:2024-08-25 15:37:50浏览次数:8  
标签:AtCoder 10 ll long ABC368 368 pair operatorname define

[ABC368F] Dividing Game

题意:

有 \(n\) 堆石子,第 \(i\) 堆有 \(a_i\) 颗石子,每次可以拿走任意一堆石子数量任何数量的棋子,但是要保证拿走之后该堆的石子数量为原来的约数(不能不拿)。

问是先手必胜还是后手必胜。

\(n,a_i \le 10^5\)。

思路:

发现与 Nim 游戏类似,且全局信息公开,状态有限,故为公平组合游戏。

考虑构造必胜状态,设 \(\operatorname{F}(a) = \operatorname{xor}\limits_{i=1}^n \operatorname{f}(a_i)\),若 \(a_i = \prod\limits_{i=1}^k p_i^{q_i} (p_i \in prime)\),则 \(\operatorname{f}(a_i) = \sum\limits_{i=1}^k q_i\)。

手玩后容易发现:

  • 当 \(\operatorname{F}(a) \ne 0\) 时为必胜态

  • 当 \(\operatorname{F}(a) = 0\) 时为必败态

考虑证明。

  • 当游戏无法进行时,即 \(a = \{1,1,\cdots,1,1\}\) 时,因为 \(1\) 没有质因子,故 \(\operatorname{f}(1)=0\),因为任意个 \(0\) 异或都得 \(0\),故 \(\operatorname{F}(a) = 0\),该状态为必败态

  • 若当前为必胜态,故绝对可以通过一些策略,使得下一个状态为必败态

    • 定义 \(\operatorname{F}(a)\) 二进制为 \(1\) 的最高位为 \(k\)。

    • 则必然有一个 \(\operatorname{f}(a_i)\) 的第 \(k\) 位为 \(1\)。

    • 考虑令 \(\operatorname{f}(a_i)' \gets \operatorname{f}(a_i) \operatorname{xor} \operatorname{F}(a)\),因为 \(\operatorname{F}(a)\) 的最高位为 \(k\),这样就消去了 \(\operatorname{f}(a_i)\) 第 \(k\) 位的值,因为 \(2^i > \sum_{i=0}^{i-1} 2^i\),故 \(\operatorname{f}(a_i) \operatorname{xor} \operatorname{F}(a) < \operatorname{f}(a_i)\)。

    • 现在我们来考虑下是否可以取石子使得 \(\operatorname{f}(a_i)\) 变为小于它的任何数,容易发现是可以的,我们可以除掉任意质因子的任意次幂。

    • 此时 \(\operatorname{F}(a)' = \operatorname{f}(a_1) \operatorname{xor} \operatorname{f}(a_2) \cdots \operatorname{f}(a_i) \operatorname{xor} \operatorname{F}(a) \operatorname{xor} \operatorname{f}(a_{i+1}) \cdots \operatorname{f}(a_n) = \operatorname{F}(a) \operatorname{xor} \operatorname{F}(a) = 0\)。

    • 此时的后继状态 \(\operatorname{F}(a)'\) 就是必败态了。

  • 若当前为必败态

    • 即 \(\operatorname{F}(a) = 0\),即所有 \(\operatorname{f}(a_i)\) 中二进制第 \(j\) 位为 \(1\) 数量为偶数,那么我们无论如何改变,肯定有至少一位的奇偶性发生变化,使得后继状态 \(\operatorname{F}(a)' \ne 0\),为必胜态

这样我们证明了只有当 \(\operatorname{F}(a) \ne 0\) 时,先手必胜。

那么可以使用线性筛筛出每个数是被哪个质数给筛掉的,就可以快速求出一个数的所有质因子幂次之和

时间复杂度为 \(O(N \log W)\)。

上面是给博弈论小白看的,但是如果您对博弈论颇为熟练,在发现我们可以将一个数的所有质因子幂次之和变为任何比它小的数时,就转化为了以所有质因子幂次之和为石子数的 Nim 游戏。

Code:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
#define _For(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
const ll N=1e5+10;
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
          f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void write(ll x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9)
	  write(x/10);
	putchar(x%10+'0');
}
ll cnt;
ll P[N],F[N];
bool f[N];
void init(){
    For(i,2,N-1){
        if(!f[i]){
            P[++cnt]=i;
            F[i]=i;
        }
        For(j,1,cnt){
            if(i*P[j]>=N)
              break;
            F[i*P[j]]=P[j];
            f[i*P[j]]=1;
            if(i%P[j]==0)
              break;
        }
    }
}
int main(){
    init();
	int N;
	cin >> N;
	vector<int> A(N);
	for (int i = 0; i < N; i++){
		cin >> A[i];
	}
	int g = 0;
	for (int i = 0; i < N; i++){
		if (A[i] == 1){
			continue;
		}
		int c = 0;
        while(A[i]>1){
            A[i]/=F[A[i]];
            c++;
        }
		g ^= c;
	}
	if (g != 0){
		cout << "Anna" << endl;
	} else {
		cout << "Bruno" << endl;
	}
}

[ABC368G] Add and Multiply Queries

题意:

给定两个长度为 \(n\) 的序列 \(a,b\),进行 \(m\) 次操作,需要支持 \(a,b\) 的单点修,进行多次区间查询:

  • 按顺序从 \(l\) 走到 \(r\),初始 \(v=0\),设当前走到第 \(i\) 个位置,可以令 \(v\) 变为 \(v + a_i\) 或 \(v \times b_i\),问最后能取的最大值(答案 \(\le 10^{18}\))。

\(n,m \le 2 \times 10^5\)。

思路:

本题加强版。

注意到 \(ans \le 10^{18}\),则如果中间都选乘的话,满足 \(b_i > 1(i \in [l,r])\) 的 \(i\) 最多只有 \(\log ans\) 个。

那么在查询区间 \([l,r]\) 的贡献时,先令 \(v = a_l\),然后再 \([l+1,r]\) 中二分出第一个 \(b_j > 1\) 的 \(j\),对于 \([l+1,j-1]\) 范围内的肯定都是选加,然后取 \(v \gets \max(v+a_j,v \times b_j)\) 即可;后面依次。

考虑使用 set 维护所有 \(b_i > 1\) 的 \(i\),使用树状数组维护前缀和即可。

时间复杂度为 \(O(N \log N \log W)\)。

Code:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
#define _For(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
const ll N=1e5+10;
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
          f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void write(ll x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9)
	  write(x/10);
	putchar(x%10+'0');
}
ll n,q,op,p,x,y,v;
ll a[N],b[N],t[N];
set<ll> S;
void add(ll x,ll v){
    for(int i=x;i<=n;i+=lowbit(i))
      t[i]+=v;
}
ll query(ll x){
    ll ans=0;
    for(int i=x;i;i-=lowbit(i))
      ans+=t[i];
    return ans;
}
int main(){
    n=read();
    For(i,1,n){
        a[i]=read();
        add(i,a[i]);
    }
    For(i,1,n){
        b[i]=read();
        if(b[i]>1)
          S.insert(i);
    }
    q=read();
    while(q--){
        op=read(),x=read(),y=read();
        if(op==1){
            add(x,-a[x]);
            a[x]=y;
            add(x,a[x]);
        }
        else if(op==2){
            if(y>1&&b[x]<2)
              S.insert(x);
            if(y<2)
              S.erase(x);
            b[x]=y;
        }
        else if(op==3){
            v=a[x];
            p=x+1;
            while(p<=y){
                auto it=S.lower_bound(p);
                if(it==S.end()||(*it)>y){
                    v+=query(y)-query(p-1);
                    p=y+1;
                }
                else{
                    ll h=(*it);
                    v+=query(h-1)-query(p-1);
                    p=h+1;
                    v=max(v+a[h],v*b[h]);
                }
            }
            write(v);
            putchar('\n');
        }
    }
    return 0;
}

标签:AtCoder,10,ll,long,ABC368,368,pair,operatorname,define
From: https://www.cnblogs.com/rgw2010/p/18378963

相关文章

  • ABC368
    A.Cut模拟代码实现#include<bits/stdc++.h>#definerep(i,n)for(inti=0;i<(n);++i)usingnamespacestd;intmain(){intn,k;cin>>n>>k;vector<int>a(n);rep(i,n)cin>>a[i];r......
  • Hitachi Vantara Programming Contest 2024(AtCoder Beginner Contest 368)- C
    题意概述有\(N\)个数,分别为\(H_1,H_2,H_3……H_N\)。你将使用初始化为\(0\)的变量\(T\)重复以下操作,直到所有数的值都变为\(0\)或更少。将\(T\)增加\(1\)。然后,减少最前方\(H_i\)值大于等于\(1\)的值。如果\(T\)是\(3\)的倍数,\(H_i\)的值会减少\(3\);......
  • ATcoder368D题详解
    D题传送门一道很无脑的题,但考试没写出来爆搜首先看朴素算法1.从根节点开始遍历每个节点2.遇到要保存的节点就进行标记,直到所有保存节点都标记时间复杂度\(O(n)\)其实已经能过了,但我没用(doge)树链剖分(LCA)首先分析1.每一次砍掉枝叶,都是在没有要保存的节点存在子树上时2.......
  • AtCoder Beginner Contest 368
    A-Cut(abc368A)题目大意给定一个数组,将右边\(k\)个数保持原顺序挪到左边,输出。解题思路即从左边第\(n-k\)个数开始输出即可。或者用rotate函数转换一下。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=longlong;intmain(void){ios::s......
  • abc368 题解
    切了ABCDF,G赛后1min切了(恼比赛链接:https://atcoder.jp/contests/abc368A-Cut题意:给定一个长度为\(n\)的序列,先输出后\(k\)个数,在输出前\(n-k\)个数。思路:按题意模拟即可。代码:https://atcoder.jp/contests/abc368/submissions/57030066B-Decrease2maxel......
  • ABC 368D Minimum Steiner Tree
    题意给你一颗由N个点组成的树,指定K个节点,求包含这K个节点的最小子树的大小思路考虑正难则反,我们从开始的树当中剪掉那些没有任何指定点的子树,剩下来的子树就是最小的、能包含所有指定节点的子树。关于剪去这个操作,就是dfs一旦遇到以当前节点为根的子树没有任何指定点时,就停止df......
  • ABC 368DF
    摆烂场,唉唉D做这题的时候总想着避免所需点形成一棵子树的情况,感觉处理不出来就去摆烂了。。。忘了自己在下面已经处理过了,根节点一定是所需点之一,在这个前提下只需要回溯的时候判断当前点的子树中有没有所需点,有的话就要加入所求树。F蛮简单的F,赛后看了看,大概10分钟切掉......
  • AtCoder Beginner Contest 368 补题记录(A~D,F,G)
    被伟大的G创似辣。Asignedmain(){intn,k;cin>>n>>k;F(i,1,n)cin>>a[i];queue<int>stk;G(i,n,1)stk.push(a[i]);while(k--){intt=stk.front();stk.push(t);stk.pop();}stack<int>......
  • AtCoder Beginner Contest 049
    A-UOIAUAI#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ ios::sync_with_stdio(false),cin.tie(nullptr); charc; cin>>c; if(c=='a'||c=='e'||c=='i'||c==�......
  • AtCoder Beginner Contest 367 A ~ F(无D题)题解
    AtCoderBeginnerContest367A~F(̸\notD)几天前就已经vp过了,但是忘写题解了今天才想起来痛,早知道这么简单,我就不在家里摆烂了A.ShoutEveryday罚了好几发,我打比......