首页 > 其他分享 >Atcoder Beginner Contest 380 (D~G)

Atcoder Beginner Contest 380 (D~G)

时间:2024-12-09 09:45:42浏览次数:9  
标签:Atcoder Beginner int father 380 maxn new dp 逆序

D.Strange Mirroring

题意:
给定一个只含有大小写字母的字符串 $ S $。
现在对这个字符串操作无数次:

  • 对于 $ S $ 的每个字符,若是大写字母就改为对应的小写字母,否则改成对应的大写字母,形成一个新的字符串 $ T $。
  • 将 $ S $ 和 $ T $ 首尾连接,形成新的 $ S $。

现在给定 $ Q $ 次询问 $ K_i $,表示询问完成上述操作后 $ S $ 的第 $ K_i $ 个字符。

题解:
下面所有的序号从0开始
结论:
对于第 $ i $ 个字符串段,若 $ bitcount(i) $ 为奇数,那么是逆反字符串;反之为正常字符串。
简单证明(?):
我们发现每一次操作实际上是所有的序号在二进制下向高位拓展了一位,前半序号这一位为 $ 0 $ ,后一半这一位为 $ 1 $ 。我们发现这实际上是 $ bitcount(i) $取2的模。

所以只需要找到 $ K_i $ 所处在的字符串段,然后根据上述规律用__builtin_popcountll()即可得到答案(一定要用popcountll)。

关于 $ bitcount(i) $对2取模后的序列,其实是Thue-Morse序列,这里插个链接供以后学习:

https://zhuanlan.zhihu.com/p/385807077

代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	string s;
	cin>>s;
	int q;
	cin>>q;
	int len=s.length();
	string t=s;
	for(int i=0;i<s.length();i++)
	{
		if(s[i]>='a'&&s[i]<='z') t[i]=(char)(s[i]-'a'+'A');
		else if(s[i]>='A'&&s[i]<='Z')t[i]=(char)(s[i]-'A'+'a');
	}
	s=' '+s;
	t=' '+t;
	while(q--)
	{
		int k;
		cin>>k;
		int which;
		if(k%len==0) which=k/len;
		else which=k/len+1;
		which--;
		int pos=k%len;
		if(pos==0) pos=len;
		int much=__builtin_popcountll(which);
        much%=2;
		if(!much) cout<<s[pos]<<' ';
		else cout<<t[pos]<<' ';
	}
	
	
	
	return 0;
 } 

E.1D Bucket Tool

题意:
给出编号从 $ 1 $ 到 $ n $ 的 $ n $ 个格子,初始第 $ i $ 个格子的颜色为 $ i $ ,接着需要你维护两种操作,第一种操作是将 $ x $ 所在的色块 (与第 $ x $ 个格子颜色相同且包含第 $ x $ 个格子的最大区间)全涂上颜色 $ c $ ,第二种操作是输出颜色为 $ c $ 的格子数量。

题解:
考虑并查集,我们只需要维护对于某一个并查集,其 $ father $ 的颜色 ,该并查集的大小,以及该并查集(实际上就是一个色块)的最左侧与最右侧的下标即可。每一次更改颜色时,只需要改变 $ father $ 的颜色,此外,由于更改颜色可能会导致并查集的扩大,这个时候就要和左侧的相邻色块以及右侧的相邻色块进行讨论与合并。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int maxn=5e5+10;
int fa[maxn],sz[maxn];
int num[maxn],col[maxn];
int Left[maxn],Right[maxn];

int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}

void hb(int x,int y)
{
	int fa1=find(x);
	int fa2=find(y);
	if(fa1==fa2) return ;
	fa[fa2]=fa1;
	sz[fa1]+=sz[fa2]; 
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		fa[i]=col[i]=i,sz[i]=num[i]=1;
		Left[fa[i]]=i;
		Right[fa[i]]=i;
	}
	while(q--)
	{
		int type;
		cin>>type;
		if(type==1)
		{
			int x,c;
			cin>>x>>c;
			int father=find(x);
			int color=col[father];
			num[color]-=sz[father];
			num[c]+=sz[father];
			col[father]=c;
			if(Left[father]-1>=1&&col[find(Left[father]-1)]==c)
			{
				int new_left=Left[find(Left[father]-1)];
				hb(father,Left[father]-1);
				Left[father]=new_left;
			}
			if(Right[father]+1<=n&&col[find(Right[father]+1)]==c)
			{
				int new_right=Right[find(Right[father]+1)];
				hb(father,Right[father]+1);
				Right[father]=new_right;
			}
		}
		else 
		{
			int c;
			cin>>c;
			cout<<num[c]<<endl;
		}
	}
	
	return 0;
 } 

F.Exchange Game

题意:
$ Takahashi $ 和 $ Aoki $ 在玩一个卡牌游戏,每张卡牌上写有一个数字。
初始时 $ Takahashi $ 有 $ N $ 张牌, $ Aoki $ 有 $ M $ 张牌,桌上还有 $ L $ 张牌。游戏规则如下:

  • 轮到某个玩家的回合时,该玩家从手中打出一张牌(记为 $ K $ )放置在桌子上,并允许在桌子上拿不超过一张小于 $ K $ 牌。
  • 当一个玩家不能进行上述操作时,对方获胜,游戏结束。

若 $ Takahashi $ 先手,双方都知道所有牌的布局,问最优策略下谁是必胜者。

$ N + M + L ≤ 12 $

题解:
令 $ S = N + M + L $ 观察到 $ S $ 是不超过 $ 12 $ 的。那么直接三进制状压 $ dp $。设 $ dp[s][1/2] $ 为,当前牌的分布状态为 $ s $ ,当前是 $ 1/2 $ 号玩家作为先手是否存在必胜策略,直接进行转移就行了,搜索末态就是当一位选手手中无牌的时候,该玩家必输。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int maxn=1600000;
int mi[20],val[20];
int n,m,l;
int dp[maxn][3];//dp[i][1/2]代表状态为i时,1/2先手是否会win

int dfs(int s,int x)
{
	if(dp[s][x]) return dp[s][x];
	vector<int>mine,all;
	for(int i=0;i<n+m+l;i++)
	{
		int which=s/mi[i]%3;
		if(which==x) mine.push_back(i);
		if(which==0) all.push_back(i);
	}
	if(mine.size()==0)
	{
		if(x==1) dp[s][x]=-1;
		else dp[s][x]=1;
		return dp[s][x];
	}
	for(auto it1:mine)
	{
		int s_new=s-x*mi[it1];
		dp[s_new][(x==1?2:1)]=dfs(s_new,(x==1?2:1));
		if((dp[s_new][x==1?2:1]==1&&x==1)||(dp[s_new][x==1?2:1]==-1&&x==2)) return dp[s][x]=dp[s_new][x==1?2:1];
		for(auto it2:all)
		{
			if(val[it1]>val[it2])
			{
				int new_s=s;
				new_s-=x*mi[it1];
				new_s+=x*mi[it2];
				dp[new_s][(x==1?2:1)]=dfs(new_s,(x==1?2:1));
				if((dp[new_s][x==1?2:1]==1&&x==1)||(dp[new_s][x==1?2:1]==-1&&x==2)) return dp[s][x]=dp[new_s][x==1?2:1];
			}
		}
	}
	return dp[s][x]=(x==1?-1:1);
} 

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	mi[0]=1;
	for(int i=1;i<=15;i++) mi[i]=mi[i-1]*3;
	cin>>n>>m>>l;
	for(int i=0;i<n+m+l;i++) cin>>val[i];
	int s0=0;
	for(int i=0;i<n;i++) s0+=mi[i]*1;
	for(int i=n;i<n+m;i++) s0+=mi[i]*2;
	dfs(s0,1);
	if(dp[s0][1]==1) cout<<"Takahashi"<<endl;
	else if(dp[s0][1]==-1) cout<<"Aoki"<<endl;
	
	return 0;
}

G.Another Shuffle Window
题意:
给定一个排列 $ P=(1,2...,N)$ 和一个整数 $ K $。
请计算经过以下操作后,排列 $ P $的逆序对数的期望值:

  • 首先,从 $ 1 $ 到 $ N-K+1 $ 的整数中随机均匀地选择一个整数 $ i $;
  • 然后,将子数组 $ p_i,p_{i+1},...,p_{i+k-1} $进行随机均匀打乱。

题解:
先给出结论,对于长度为 $ N $ 的排列,将其均匀打乱后产生的逆序对期望为 $ N(N+1)/4 $ 。
证明:
对于长度为 $ N $ 的排序,一共可以产生 $ N(N+1)/2 $ 对二元关系,而每对二元关系产生逆序对的期望为 $ 0.5 $ ,那么对于长度为 $ N $ 的排列,将其均匀打乱后产生的逆序对期望为 $ N(N+1)/4 $。
那么我们现在只需要求出长度为 $ N $ 的数组中的 $ N-K+1 $ 个长度为 $ K $ 的子数组中各自的逆序对为多少即可。我们先预处理出 $ P_1 $ 到 $ P_K $ 中产生的逆序对的个数,我们在向右平移的过程中,每次只需要减去 $ P_i $ 的逆序对,加上 $ p_{i+k} $ 产生的逆序对就可以得到新的逆序对总和了。最后将这 $ N-K+1 $ 个总和累加起来除以 $ N-K+1 $ ,最后加上 $ N(N+1)/4 $ 就可以得到正确结果了。

代码:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int mod=998244353;
const int maxn=2e5+10;
int tree[maxn],p[maxn],n,k;

int fast_pow(int a,int n,int mod)
{
	int ans=1;
	a%=mod;
	while(n)
	{
		if(n&1) ans=(ans*a)%mod;
		a=(a*a)%mod;
		n>>=1;
	}
	return ans;
}

int inv(int a,int mod)
{
	return fast_pow(a,mod-2,mod);
}

int lowbit(int x)
{
	return x&(-x);
}

void add(int x,int k)
{
	while(x<=n)
	{
		tree[x]+=k;
		x+=lowbit(x);
	}
}

int query(int x)
{
	int ans=0;
	while(x)
	{
		ans+=tree[x];
		x-=lowbit(x);
	}
	return ans;
}


signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>p[i];
	int sum=0;
	for(int i=n;i>=1;i--)
	{
		sum+=query(p[i]);
		add(p[i],1);
	}
	memset(tree,0,sizeof(tree));
	int now=0;
	for(int i=k;i>=1;i--)
	{
		now+=query(p[i]);
		add(p[i],1);
	}
	int ans=sum-now;
	for(int i=1;i<=n-k;i++)
	{
		add(p[i],-1);
		now-=query(p[i]);
		now+=query(n)-query(p[i+k]);
		add(p[i+k],1);
		ans=(ans+sum-now)%mod;
	}
	cout<<(ans*inv(n-k+1,mod)+k*(k-1)%mod*inv(4,mod))%mod<<endl;
	
	return 0;
}

标签:Atcoder,Beginner,int,father,380,maxn,new,dp,逆序
From: https://www.cnblogs.com/lulu7/p/18592098

相关文章

  • [题解](更新中)AtCoder Beginner Contest 383(ABC383) A~E
    A-Humidifier1照题意模拟即可,时间复杂度\(O(n)\)。点击查看代码#include<bits/stdc++.h>#defineintlonglong#defineN110usingnamespacestd;intn,t[N],v[N],sum;signedmain(){ cin>>n; for(inti=1;i<=n;i++)cin>>t[i]>>v[i]; for(inti=1......
  • 【Atcoder】【ABC383】A- Humidifier 1加湿器 题解
    前言不知道大家有没有关注过AtCoder这是小日子那边的一个网站,每周都会有比赛比起CF等等,最大的优点就是延迟低,题目质量也不错计划以后每周更新题解了正文题目传送门A-Humidifier1题目大意有一个加湿器,给定有次操作,第次在时间加入胜水然而,如果加湿器里有水,它每个单......
  • Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)-C
    题目大意一个\(H\)行和\(W\)列的网格图。\((i,j)\)表示从上到下第\(i\)行和从左到下第\(j\)列的单元格。每个单元格用字符\(S_{i,j}\)表示。如果\(S_{i,j}\)为#,则该单元格有一个障碍物;如果\(S_{i,j}\)是.则该单元格是空的;如果\(S_{i,j}\)为H,则该单元网格图......
  • AtCoder Beginner Contest 383 赛后复盘
    C>>>>>>>>D。A模拟即可。B唯一坑点是被染湿的格子不一定要和加湿器连通,枚举两个加湿器然后计算所有点即可,时间复杂度\(O(h^3m^3)\)。点击查看代码#include<bits/stdc++.h>#definelllonglong#definei128__int128#definemem(a,b)memset((a),(b),sizeof(a))#def......
  • atcoder 杂题 #02
    atcoder杂题#02arc065_bConnectivity。arc137_bCount1's。abc287_fComponents。abc308_gMinimumXorPairQuery。arc065_b对两种边分别建图求并查集,其实就是求有多少个点满足两个图都在同一个并查集。可以把一个点的并查集标号扔进map<pair<int,int>,int>里,就......
  • 题解:AtCoder Beginner Contest AT_abc380_d ABC380D Strange Mirroring
    题目大意给定一个字符串$S$,执行$10^{100}$次以下操作:首先,令字符串$T$为字符串$S$中所有大写字母变为小写字母,小写字母变为大写字母的结果。其次,将$T$拼接在$S$后面。接下来,有一些询问:请输出在所有操作执行完成之后$S$的第$K$个字母。思路乍一看,好大的数......
  • 题解:AtCoder Beginner Contest AT_abc373_d ABC373D Hidden Weights
    题目传送门题目翻译给你一个$N$个点,$M$条边的有向图,其中边有边权。现在让你给每一个点设置一个点权$a$,使得对于任意两点$x$和$y$,如果$x$到$y$有一条边,边权为$w$,那么需要满足$a_y-a_x=w$。现在让你输出一组合法的分配方案,题目保证存在,输出任意一组都行。思路1(注意......
  • atcoder 杂题 #01
    atcoder杂题#01arc163_cHarmonicMean。arc065_cManhattanCompass。abc303_fDamageoverTime。arc065_dShuffling。arc163_c可能因为数学不好,所以栽在了这道Luogu评的绿题上。题目大意:求一个长为\(n\)的正整数序列\(a\)使得\(\sum\frac1{a_i}=1\),要求......
  • 1.1 Beginner Level学习之“了解 ROS 服务和参数”(第七节)
    学习大纲:1.ROS服务ROS服务是一种节点之间的通信方式,允许一个节点发送请求并接收响应。它采用的是同步机制,即一个节点会发送请求,等待另一个节点处理并返回结果。这个机制适合需要及时反馈的情况。rosservice是ROS提供的一个工具,专门用来与服务进行交互。它可以列出、查......
  • abc380D Strange Mirroring
    给定字符串S,每次操作会复制一份并改变大小写追加到原字符串后面。有Q组询问,每次输出K[i],输出结果中第K[i]个字符是什么?1<=|S|<=2E5,1<=Q<=2E5,1<=K[i]<=1E18分析:依次处理每个询问,先倍增到能覆盖询问的长度,然后倒推出该字符由S的哪个字符得到,以及大小写状态。#include<bits/s......