AtCoder Beginner Contest 276

130 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

A

Problem Statement

You are given a string S consisting of lowercase English letters.
If a appears in S, print the last index at which it appears; otherwise, print −1. (The index starts at 1.)

Constraints

  • S is a string of length between 1 and 100 (inclusive) consisting of lowercase English letters.

题意:找最后一个a的位置

思路:水题,从后向前第一个碰到a就输出,或者从前到后碰到a就更新。

B

题意:找每一位后面都有谁

思路:按存图的方式来就可以了

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1e5 + 10;
vector<int>s[N];
int main()
{
	int n,m;
	cin >>n >> m;
	for(int i = 1;i <= m;i ++)
	{
		int x,y;
		cin >> x >> y;
		s[x].push_back(y);
		s[y].push_back(x);
	}
	for(int i = 1;i <= n;i ++)
	{
		if(!s[i].size())
		{
			cout << 0 << '\n';
			continue;
		}
		sort(s[i].begin(),s[i].end());
		cout << s[i].size() << ' ';
		//cout << s[i][0]<<'\n';
		for(int j = 0;j < int(s[i].size());j ++)
		cout << s[i][j] << ' ';
		cout << '\n';
	}
}

C

给定一个 1∼n的排列 p,已知 p 是 1∼n 的所有排列中字典序排名第 k 小的,求字典序第 k−1 小的排列。

思路:stl的函数

STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation。

next_permutation去找下一个排列组合P+1,找到则排列为下一个排列组合返回true,否则数组变成字典序最小的排列组合(即为重置排列)并返回false,prev_permutation也是一样的

代码:

 vector<int> p(n);
 for (int i = 0; i < n; ++i) {
    cin >> p[i];
  }
  prev_permutation(p.begin(),p.end());

D

Problem Statement

You are given a sequence of positive integers: A=(a1​,a2​,…,aN​).
You can choose and perform one of the following operations any number of times, possibly zero.

  • Choose an integer i such that  N1≤i≤N and ai​ is a multiple of 2, and replace ai​ with {2}2ai​​.
  • Choose an integer i such that N1≤i≤N and ai​ is a multiple of 3, and replace ai​ with {3}3ai​​.

Your objective is to make A satisfy a1​=a2​=…=aN​.
Find the minimum total number of times you need to perform an operation to achieve the objective. If there is no way to achieve the objective, print -1 instead.

题意

给定 n 个数 a1∼an,一次操作可以选择一个数除以 2 或 3(必须是 2 或 3 的倍数),问使得所有数都相等的最小操作次数

思路:dfs走能被3整除,2整除的情况就好了

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
ll a[N];
map<ll,ll>mp1;
void dfs(int u)
{
	if(u%3 == 0 && u)
	{
		dfs(u/3);
		if(!mp1[u/3])
		mp1[u/3]++;
	}
	if(u%2 == 0 && u)
	{
		dfs(u/2);
		if(!mp1[u/2])
		mp1[u/2]++;
	}
	return ;
}
int main() {
    int n;
    cin >> n;
    map<ll,ll> mp;
    for(int i = 1;i <= n;i ++)
    {
    	cin >> a[i];
    	mp1.clear();
    	mp1[a[i]]++;
    	int x = a[i];
    	dfs(x);
    	for(auto [a,b]:mp1)
	    {
	    	mp[a] ++;
	    }
    }
    int x = 0;
    for(auto [a,b]:mp)
    {
    	if(b == n)
    	x = a;
    }
    if(x)
    {
    	int res = 0;
    	for(int i = 1;i <= n;i ++)
    	{
    		int cnt = 0;
    		int pos = a[i]/x;
    		while(pos%3 == 0&&pos)
    		{
    			pos/=3;
    			cnt ++;
    		}
    		while(pos%2 == 0&&pos)
    		{
    			pos/=2;
    			cnt ++;
    		}
    		res += cnt;
    	}
    	cout << res << '\n';
    }
    else
    cout << "-1" << '\n';
}

E

给一个n*m的图,要求能从x,y走到x,y有不同的路可以组成一个矩形

思路:dfs往四个方向走

代码:

inline void dfs(int x,int y,int dep){
     vis[x][y]=dep;
      for (int i=0;i<4;++i){
          int tx=x+dx[i];
          int ty=y+dy[i];
          if (tx<1 || ty<1 || tx>n || ty>m || s[tx][ty]=='#') continue;
          if (tx==ttx && ty==tty && abs(vis[tx][ty]-vis[x][y])+1>=4) res=1;
          if (vis[tx][ty]) continue;
          dfs(tx,ty,dep+1);
         }
}

F

Problem Statement

There are N cards called card 1, card 2,… card N. On card i(1≤i≤N)`,

For K=1, 2,……, N。K=1,2,…,N, solve the following problem.

We have a bag that contains K cards: card 1, card 2, card K.
Let us perform the following operation twice, and let x and y be the numbers recorded, in the recorded order.

Draw a card from the bag uniformly at random, and record the number written on that card. Then, return the card to the bag.

Print the expected value of max(x,y), modulo 998244353 (see Notes).
Here, max(x,y) denotes the value of the greater of x and y (or x` if they are equal).

题意:

就是给你n张牌输出n行代表每一行有n张牌在盒子里,例如n = 1,你有1张牌,然后从盒子里抽两张牌,注意抽一次要放回一次,一个抽两次,记录这两次的最大值然后一个抽i回,让所以的最大值相加再除以i的平方sum,求sum与mod的同余数ans

思路:

先将期望转化为总和除以总次数,总次数显然为 k^2,只考虑计算总和。

然后你会发现每次都会抽他一次本身,然后前面比i小的数都要2a[i],比i大的数x都要2a[x];

所以可以树状数组求前面比小于a[i]的个数res ,比a[i]大的数的和pos;

然后把他们乘2在除以i的平方;

ans+2×(a[i]×res+pos)/i^2;

代码

#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int N = 2e6 + 10;
const int md = 998244353;
int a[N],c[N],sum[N];
int n;
ll power(ll x,ll y)
{
	x %= md;
	ll ans = 1;
	for(;y;y >>= 1) {
		if(y & 1)(ans *= x) %= md;
		(x *= x) %= md;
	}
	return ans;
}
int lowbit(int x) {
	return x & -x;
}
 
void add(int x,int y) {
	for(;x <= N;x += lowbit(x))
		++ c[x],(sum[x] += y)%=md;
	return ;
}
 
int querynum(int x) {
	int res = 0;
	for(;x;x -= lowbit(x))
		res += c[x];
	return res;
}
 
ll querysum(int x) {
	ll ans = 0;
	for(;x;x -= lowbit(x))
		(ans += sum[x])%=md;
	return ans;
}
int main()
{
	int n;
	cin >> n;
	ll ans = 0, val = 0;
	for(int i = 1;i <= n;i ++)
	{
		cin >> a[i];
		ans += a[i]; ans%= md;
		val += 2ll * a[i] * querynum(a[i]) % md;
		val%=md;
		val += 2ll * (querysum(N) - querysum(a[i]) + md)%md%md;
		val%=md;
		ll res = ((ans + val) % md * power(1ll * i * i, md - 2) % md)%md;
		printf("%lld\n", res);
		add(a[i],a[i]);
	}
}