首页 > 其他分享 >atcoder350,351,352,353,354,355期部分题解

atcoder350,351,352,353,354,355期部分题解

时间:2024-06-01 19:28:42浏览次数:26  
标签:10 cnt 题意 int 题解 ll 355 354 ans

声明:有些题感觉已经说到很明白了,就先不写代码了,有空会补上

目录

350D: new friend

350E: toward 0

351D:Grid and Magnet

352D:permutation  subsequence

353C: sigma problem

353D: another sigma problem

354C: atcoder magics

355C: bingo2

355D: intersecting intervals 

附加题:火烧赤壁


希望读者可以有所收获 

        

        

350D: new friend

就是问你,最终有多少对这种关系:x和y是朋友,y和z是朋友,但是x和z不是朋友。你也把这种关系理解成y是中介方,但是我们要明白一点,x和y和z一定是在同一个联通块中。所以选点一定就是在联通块中选择。

也就是说:在同一个联通块中,如果x和y是朋友关系,那么它们不满足题意;如果x和y不是朋友关系,那么它们就满足题意。所以我们只需要找所有联通块中有多少对新朋友,加起来,然后减去原来的朋友数即可。

(为什么我会想到联通块呢?因为在我们做题的时候,尤其是图论,一定要尽量把题给抽象一下,你才能想到考察的知识点)

最后,要求联通块中的新朋友对数,就需要求联通块中的点数,我们可以dfs跑联通块,然后返回这个联通块中的点数,同时给遍历过的点打上标签,然后去跑别的联通块;我们也可以直接并查集来做,维护祖宗节点的cnt值,存放该集合的点数。

        

        

350E: toward 0

题意:给一个N,然后每轮有两种操作,一个是花费x变成[N/A],另一个是花费y变成[N/b],b等概率取1,2,3,4,5,6。 

分析:一道期望dp,感觉和概率dp差不多,大致思路都是dp[起始状态]=初始概率或者初始期望,然后找每轮之间的关系进行转移,一直dp到最终状态就行了。

我们先找每轮之间的关系:

我们设置f[N]表示N变成0的期望花费,初始f[0]=0

f[N]=Y+(f[N/6]+f[N/5]+f[N/4]+f[N/3]+f[N/2]+f[N/1])/6

修改一下变成:f[N]=6/5*Y+(f[N/6]+f[N/5]+f[N/4]+f[N/3]+f[N/2])/5

所以:f[N]=min(X+f[N/A],6/5*Y+(f[N/6]+f[N/5]+f[N/4]+f[N/3]+f[N/2])/5)

接下来就是转移就完事了,明显借助dfs来完成转移更加方便。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
unordered_map<ll,double>mp;
ll N,A,X,Y;
double f(ll x){
	if(x==0)return 0; //初始值
	if(mp.count(x))return mp[x]; //记忆化
	double ret2=0,ret1=f(x/A)+X;
	for(int i=2;i<=6;i++)ret2+=f(x/i);
	ret2=(ret2+6*Y)/5;
	return mp[x]=min(ret1,ret2);
}
int main(){
	cin>>N>>A>>X>>Y;
	printf("%.9f",f(N));
}

代码为什么要用double呢?因为存在性质:[[N/a]/b]=[N/ab],所以要保持精度。 

        

        

351D:Grid and Magnet

 题意:HxW的网格,' . '代表可以走,' # '代表有磁铁,会吸住上下左右的格子,导致不能再移动,要求输出从某一个点能走的最多格子。

考的还是联通块,我们可以把每个磁铁周围会被吸住的格子打上标记,然后我们去搜图中的每一个联通块,并统计每个联通块的块数,最后输出最大的块数即可。

        

        

352D:permutation  subsequence

题意:有一个序列1~n的某一排序,我们要在此排序中找到长度最小的包含长度为k的任意自然数段。

我这里强调一下这种自然数某一排序题的常见思路:就是分析pos数组,pos数组就是每个数的位置信息。

比如:10 1 6 8 7 2 5 9 3 4   构造pos数组如下:

数组:2 6 9 10 7 3 5 4 8 1(表示每个1~n的位置信息)

我们开始考虑1~5的最小符合题意的长度:处理2 6 9 10 7即可,max-min=8,说明长度为8

考虑2~6:max-min=7

考虑3~7:max-min=7

考虑4~8:max-min=5

考虑5~9:max-min=5

考虑6~10:max-min=7

所以答案就是5

也就是我们只需要求出每个区间的极差即可,使用滑动窗口就可以了。

        

        

353C: sigma problem

首先要理解这个玩意:

它意思就是

    for(int i=1;i<=n-1;i++)
	for(int j=i+1;j<=n;j++){
		ans+=f(a[i],a[j]);
	}

但是我们肯定不能直接这样做,因为太慢了,那么我们就要找规律了:

那么最直接的想法就是“变加为乘”,以此来加速。

我们不难发现:全部的相加过程中:

a[1]+a[2]   a[1]+a[3]   a[1]+a[4]……a[1]+a[n]

a[2]+a[3]   a[2]+a[4]……a[2]+a[n]

……

也就是说如果我们先不考虑取模的情况时,每个数a[i]都会被加n-1次

然后我们再考虑取模的情况:

这里如果没有发现a[i]<10^8这个细节的话,估计就很难做出来了,如何使用这个条件呢?

我们会发现a[i]+a[j]在mod10^8的过程中最多也就是减去了一次10^8,所以我们在把所有的a[i]+a[j]大于10^8的个数找出来,然后减去10^8就行了。

#include <bits/stdc++.h>
using namespace std;
int a[300000];
int mod=100000000;
int main(){
	int n;cin>>n;
	long long ans=0;
	for(int i=0;i<n;i++){
		cin>>a[i];ans+=a[i]*(n-1ll);
	}
	sort(a,a+n);
	for(int i=0;i<n;i++){
		ans-=mod*1ll*(a+n-lower_bound(a+1+i,a+n,mod-a[i]));//另外一个数一定比当前的数更大,所以从a+1+i开始找
	}
	cout<<ans<<'\n';
}

        

        

353D: another sigma problem

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=998244353;
ll suf[200005],a[200005];
ll get(ll x){
	ll ans=1;
	while(x)x/=10,ans*=10;
	return ans;
}
int main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	ll ans=0;
	for(int i=n;i>=1;i--){
		suf[i]=(suf[i+1]+get(a[i]))%mod; //每个数要乘的倍率的和(后缀和)
	}
	for(int i=1;i<=n;i++){
		ans+=a[i]*(i-1)%mod;//前半部分的贡献
		ans%=mod;
		ans+=suf[i+1]*a[i]%mod;//后半部分的贡献
		ans%=mod;
	}
	cout<<ans<<'\n';
}

        

        

354C: atcoder magics

 

题意:有N张卡片,每张卡片上有A和C两个数,分别表示力量和花费,我们可以进行操作:

选择两个卡片,如果A1>A2,C1<C2,我们就丢掉2卡片。问我们最终可以剩下哪些卡片?

做这种题的一个直觉就是排序:如果我们按照A从大到小排好序后,就不用再考虑A了,只需要考虑C。如果当前的卡片C值比前面的卡片的C值都小,那就留下他,否则就丢掉这个卡片。

#include <bits/stdc++.h>
using namespace std;
struct card{
	int val,cost,id;
}a[200005];
bool cmp(card x,card y){
	return x.val>y.val;
}
int main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		int val,cost;
		cin>>val>>cost;
		a[i]={val,cost,i};
	}
	sort(a+1,a+1+n,cmp);
	int minn=2e9;
	vector<int> ans;
	for(int i=1;i<=n;i++){
		if(a[i].cost<minn){
			ans.push_back(a[i].id);
			minn=a[i].cost;
		}
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<'\n';
	for(auto i:ans){
		cout<<i<<' ';
	}
	return 0;
}

        

        

355C: bingo2

题意:有一个N*N的网格,依次填入1,2,3,4……n^2(如图),然后一共有T轮,每轮都会填一个数,问至少几轮后才有一列或者一行,或者一个对角线被填充?

考察的就是如何用vis表示一个对角线,不会的回去看看CSDN中的八皇后问题,填入一个就vis++,然后检查对应的行,列,对角线,看看什么时候可以满足题意。

        

        

355D: intersecting intervals 

 

题意:有n个区间,问你一共有多少对区间相交?

先拆开分析:

1开始 7开始 3开始

5结束 8结束 7结束

我们排序:

1开始

3开始

5结束

7开始

7结束

8结束

我们要统计每个区间开始出现的时候,已经有多少个区间存在了,那么此时就会增加多少个相交区间,也就是我们要关心目前有多少个区间往后面走,当开始出现一个区间时候cnt++,当开始减少一个区间时候cnt--

排序的时候注意相同时间开始在前,结束在后(因为在某一点都同时有开始和结束也算相交)

1开始  cnt=1

3开始  cnt=2  ans=1

5结束  cnt=1  

7开始  cnt=2  ans=2

7结束  cnt=1

8结束  cnt=0

再来一个样例

1开始  cnt=1

2开始  cnt=2  ans=1

3开始  cnt=3  ans=3

4结束  cnt=2

5结束  cnt=1

6结束  cnt=0

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
	int v,op; //op=1为结束,op=0为开始
};
vector<node>ve;
bool cmp(node x,node y){
	if(x.v==y.v)return x.op<y.op;//先返回起点再返回终点
	return x.v<y.v;
}
int main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		int l,r;cin>>l>>r;
		ve.push_back({l,0});
		ve.push_back({r,1});
	}
	sort(ve.begin(),ve.end(),cmp);
	int cnt=0;ll ans=0;
	for(int i=0;i<ve.size();i++){
		int v=ve[i].v,op=ve[i].op;
		if(op==0)ans+=cnt,cnt++;
		else cnt--;
	}
	cout<<ans<<'\n';
	return 0;
}

看完这题,建议再看一道很像的题。

        

        

附加题:火烧赤壁

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e4+10;
ll ans;
int n;
struct node{ll x;ll y;}e[N];
bool cmp(node a,node b){
	if(a.x==b.x)return a.y<b.y;
	return a.x<b.x; 
}
int main(){
	cin>>n;ll a,b;
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&a,&b);
		e[i].x=a;e[i].y=b-1;
	}
	sort(e+1,e+1+n,cmp);
	ll end=e[1].y;
	ans+=e[1].y-e[1].x+1;
	for(int i=2;i<=n;i++){
		if(end>=e[i].x){
			if(end>=e[i].y)continue;
			ans+=e[i].y-end;
			end=e[i].y;
		}
		else {
			ans+=e[i].y-e[i].x+1;
			end=e[i].y;	
		}
	}
	cout<<ans;
}

标签:10,cnt,题意,int,题解,ll,355,354,ans
From: https://blog.csdn.net/m0_69478376/article/details/139370305

相关文章

  • AtCoder Beginner Contest 355 (E,F)
    总结:这把B都错题了一直Wa,然后队友告诉我说F貌似可做,写了半个小时F发现题目读假了,于是四题下班。E-GuesstheSum题目大意:给定一个隐藏的、长度为N的数组,下标从0开始,题目给定L,R,要你用最少的询问次数求出\(\sum_{i=L}^{R}a_{i}\)。对于每次询问,可以选择一个i和j,然......
  • 【问题解决】MySQL恢复数据库报错Unknown command '\''.
    问题使用以下命令备份恢复数据库,恢复失败提示ERRORatline39595:Unknowncommand'\''.#备份数据库mysqldump-uusername-p--no-create-db-Rdatabasename>dump.sql#恢复数据库mysql-uusername-pdatabasename2<dump.sql问题原因及解法原因:中文字符的问题......
  • P6156 简单题 题解
    P6156简单题题解题目大意题目传送门给定\(n,k\),求\(\sum_{i=1}^n\sum_{j=1}^n(i+j)^k\gcd(i,j)\mu^2(\gcd(i,j))\)。\(1\leqn\leq5\times10^6\)题目分析先推导一波式子:\[\begin{aligned}ans&=\sum_{i=1}^n\sum_{j=1}^n(i+j)^k\gcd(i,j)\mu^2(\gcd(i,j))\\&=......
  • 磁盘管理后续——盘符漂移问题解决
    之前格式化磁盘安装了文件系统,且对磁盘做了相应的挂载,但是服务器重启后挂载信息可能有问题,或者出现盘符漂移、盘符变化、盘符错乱等故障,具体是dev/sda,sdb,sdc等等在某些情况下会混乱掉比如sda变成了sdb或者sdc变成了sdb等等,这样无形中会导致磁盘设备管理的混乱,最常见......
  • 2024ICPC武汉邀请赛E. Boomerang 题解
    E-Boomerang(动态维护树的直径+二分)分析代码实现#include<bits/stdc++.h>#ifdefLOCAL#include"algo/debug.h"#else#definedebug(...)42#endif#defineintlonglongusingEdge=int;structHLD{ intn,times=0; std::vector<int>siz,top,......
  • ARC119F 题解
    blog。被自动机做法恶心到了,现在也来恶心一下大家。\(\color{red}\textbf{以下内容强烈建议自己推一遍,几乎一半是重复的,推完会很爽,并且理解会很深。}\)\(\color{red}\textbf{以下内容不建议用}\LaTeX\textbf{书写,因为写起来像在吃大便。}\)暴力\(dp_{i,a,b}\)表示当前在\(......
  • 【题解】UOJ#284 快乐游戏鸡
    题目大意给出一棵有\(n\)个节点的树,编号为\(i\)的点权为\(w_i\),在树上通过一条边需要花费时间\(1\),如果能通过一个点权为\(w_i\)的点当且仅当此时的死亡次数大于等于\(w_i\),否则会立即回到起点并且死亡次数加一。给出\(q\)组询问,每组询问给出起点\(s\)和终点\(t\),......
  • CF1981D题解
    CF1981D题解前言标签:筛法,欧拉回路。赛后过的,构造一眼秒,欧拉图写错了,多少有点抽象。题意构造一个长度为\(n\)的序列\(a\),需要满足:\(\forall1\lei\len\),\(1\lea_i\le3\times10^5\)。\(\forall1\lei<j<n\),\(a_i\timesa_{i+1}\nea_j\timesa_{j+1}\)。......
  • Atcoder ABC355 C~F
    C出题人太善良了,加强到\(10^5\)都没问题。考虑维护每条横线竖线两条对角线上被标记的点的个数,每次标记点后,判断是否有线上点全被标记。再考虑如何将点编号转为坐标,记编号为\(t\),推柿子:\[(x-1)\timesn+y=t\]\[nx+y=t+n\]\[x=\frac{t+n-y}{n}\]等同于找到\(y\)使得:\[n......
  • ABC 354
    B-AtCoderJanken2本来想开\(\rmvector<pair<string,int>>\)的,但发现其实没有必要,整数部分只需求和即可。另外,多个字符串按字典序升序排序可以直接存\(\rmvector\)后\(\rmsort\)。#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmai......