《看了受制了》第四十五天,5道题合计279道题

2023年10月19日

Acwing1978 奶牛过马路

题目理解

这个题目和友好城市太像了,那个是排序一下求最长上升子序列,这个排序一下要达到:

  1. \(P_i\)前面的每一个数都要小于它
  2. \(P_i\)后面的每一个数都要大于它
    所以我们要在\(O(n)\)的复杂度内处理完需要,搞个前缀最大值和前缀最小值

代码实现

typedef pair<int, int> PII;

const int Mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;

void solve()
{

    int n;
    cin >> n;
    vector<PII> v(n);

    for(int i = 0; i < n; i++)
        cin >> v[i].x >> v[i].y;

    sort(v.begin(), v.end());
    vector<int> p(n), q(n);
    int val = -INF;
    int res = 0;
    for(int i = 0; i < n; i++)
    {
        val = max(val, v[i].y);
        p[i] = val;
    }
    val = INF;
    for(int i = n - 1; i >= 0; i--)
    {
        val = min(val, v[i].y);
        q[i] = val;
    }


    for(int i = 0; i < n; i++)
        if(v[i].y < p[i] || v[i].y > q[i])
            res++;

    cout << n - res;

    return;
}

Acwing1969 品种临近

题目理解

这个题开数组记录一下,品种的下标做差即可。

代码实现

const int N = 1e6 + 10;
int pos[N];
void solve()
{

    int n, k;
    cin >> n >> k;
    int res = -INF;
    for(int i = 1; i <= n; i++)
    {
        int a;
        cin >> a;

        if(i - pos[a] <= k && pos[a] != 0)
            res = max(res, a);
        pos[a] = i;
    }
    if(res >= 0) cout << res << endl;
    else cout << -1 << endl;
    return;
}

Acwing1987 粉刷栅栏

题目理解

是一个离散化后差分的题。我们本题练习的是用map来实现离散化。

代码实现

const int N = 1e5 + 10;
int n;
map<int, int> mp;   // map有序的

int main()
{   
    cin >> n;
    int x = 0;
    for(int i = 1; i <= n; i++)
    {
        int k;
        string s;
        cin >> k >> s;
        if(s == "R")
        {
            mp[x]++;
            mp[x + k]--;
            x += k;
        }else{
            mp[x - k]++;
            mp[x]--;
            x -= k;
        }
    }


    int res = 0, sum = 0, last;

    for(auto& [x, v] : mp)
    {
        if(sum >= 2) res += x - last;   // 
        sum += v;   // 前缀和
        last = x;
    }

    cout << res;
    return 0;
}

Atcoder ABC324 D

题目大意

问一些数字全排列后组成的数字,可以组成几个完全平方数。

题目理解

我们正向枚举的话是\(13!\)这肯定爆了,但是我们可以枚举完全平方数,因为要平方,所以只能到\(1e^7\),完全ok。然后我们统计数字出现的次数是否满足就行了。

代码实现

vector<ll> vec;
int cnt[10];
int a[10];
bool check(ll u)
{
	memset(a, 0, sizeof a);
	while(u)
	{
		a[u % 10]++;
		u /= 10;
	}
	for(int i = 1; i <= 9; i++)
		if(a[i] != cnt[i])
			return false;

	return true;
}

int len(ll u)
{
	int cnt = 0;
	while(u) u /= 10, cnt++;
	return cnt;
}

void solve()
{
	int n;
	string s;
	cin >> n >> s;
	for(int i = 0; i < n; i++)
		cnt[s[i] - '0']++;

	int res = 0;
	for(int i = 0; i < (int)vec.size(); i++)
	{
		if(len(vec[i]) > n) break;
		if(check(vec[i]))
			res++;
	}

	cout << res;

	return;
}

Atcoder ABC324 E

题目大意

给了\(N\)个字符串,两两任意组合,可以选择相同的串组合。问组合的\(N^2\)中可能中,有多少可能,里面的子序列是包含T的。

题目理解

直接枚举肯定爆了。本题学到的知识是字符串子序列的匹配:

  • 如果想判断两个串的和\(s_i + s_j\)是否为\(t\)的子序列(不连续的)
  1. 从左往右匹配看能匹配多少个字符记为\(i\)
  2. 从右往左匹配看能匹配到多少个字符记为\(j\)
  3. 只要满足\(i + j >= len(s)\)那么说明肯定\(t\)中包含。
    我们有了上述的思想后,我们便可对于\(n\)个串得到\(a和b\)两个数组,分别代表上述的从左往右的数量和从右往左的数量。
    那么问题就转化成了:
  • \(a\)\(b\)两个序列中有多少组\(a_i + b_j >= len(t)\)
    那么二分即可!也可以用那个low_bound,我记得之前那个墙的题做过。

代码实现

vector<ll> vec;
int cnt[10];
int a[10];
bool check(ll u)
{
	memset(a, 0, sizeof a);
	while(u)
	{
		a[u % 10]++;
		u /= 10;
	}
	for(int i = 1; i <= 9; i++)
		if(a[i] != cnt[i])
			return false;

	return true;
}

int len(ll u)
{
	int cnt = 0;
	while(u) u /= 10, cnt++;
	return cnt;
}

void solve()
{
	int n;
	string s;
	cin >> n >> s;
	for(int i = 0; i < n; i++)
		cnt[s[i] - '0']++;

	int res = 0;
	for(int i = 0; i < (int)vec.size(); i++)
	{
		if(len(vec[i]) > n) break;
		if(check(vec[i]))
			res++;
	}

	cout << res;

	return;
}
posted @ 2023-10-20 13:42  wxzcch  阅读(3)  评论(0编辑  收藏  举报