2024.1.23 寒假训练记录(6)

记录一个训练赛踩的大坑:往函数里传vector一定要加引用!犯了三次的错误还是记不住,服了,一道题调了一个小时。

文章目录

  • CF 1490E Accidental Victory
  • CF 1753B Factorial Divisibility
  • CF 1454E Number of Simple Paths
  • AT ARC148A mod M
  • CF 1854B Earn or Unlock
  • CF 1055A Metro
  • CF 460C Present
  • CF 894A QAQ

CF 1490E Accidental Victory

题目链接

从后往前看,每个数加上前面的所有数能不能超过后一个数,一旦有一个数不行了就直接输出前面的数即可(注意开longlong啊啊啊)

#include 

using namespace std;

typedef pair<int, int> PII;

#define int long long

void solve()
{
	int n;
	cin >> n;
	vector<PII> a(n + 1);
	for (int i = 1; i <= n ;i  ++)
	{
		cin >> a[i].first;
		a[i].second = i;
	}
	sort(a.begin(), a.end());
	vector<int> pre(n + 1);
	for (int i = 1; i <= n; i ++) pre[i] = pre[i -1 ] +a[i].first;
	vector<int> per;
	per.push_back(a[n].second);
	for (int i = n - 1; i > 0; i -- )
	{
		if (pre[i] >= a[i + 1].first) per.push_back(a[i].second);
		else break;
	}
	sort(per.begin(), per.end());
	cout << per.size() << '\n';
	for (auto i : per) cout << i << ' ';
	cout << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 1753B Factorial Divisibility

题目链接

太毒瘤了这题赛时想了老半天

先记录下分子上每个数字出现的次数然后合并,比如说3个2!就合并成一个3!这样,看最后能不能都合并成x!的倍数即可

#include 

using namespace std;

typedef pair<int, int> PII;

#define int long long

void solve()
{
	int n, x;
    cin >> n >> x;
    map<int, int> mp;
    for (int i = 0; i < n; i ++ )
    {
        int kk; cin >> kk;
        mp[kk] ++ ;
    }
    for (auto &i : mp)
    {
        if (i.first == x)
        {
            cout << "YES\n";
            return;
        }
        if (i.second % (i.first + 1) != 0) 
        {
            cout << "NO\n";
            return;
        }
        else
        {
            mp[i.first + 1] += i.second / (i.first + 1);
        }
    }
    cout << "YES\n";
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 1454E Number of Simple Paths

题目链接

晚上补题的时候发现比想象中简单,好可惜赛时没做这题啊

n个顶点n条边的图我们叫做基环树,可以想象它长这样:
2024.1.23 寒假训练记录(6)_第1张图片
我们先记录环上的点,每个环上的点引出去的子树中,两点之间都只有一条路径,然后子树和其他点之间都有两条路径(因为有个环),可以循环计算每个子树,答案累加即可

#include 

using namespace std;

typedef pair<int, int> PII;

#define int long long

void solve()
{
	int n;
    cin >> n;
    vector<vector<int>> g(n + 1);
    vector<int> in(n + 1);
    for (int i = 0 ;i < n; i ++ )
    {
        int a, b;
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
        in[a] ++ , in[b] ++ ;
    }
    queue<int> q;
    for (int i = 1; i <= n; i ++ ) 
    {
        if (in[i] == 1) q.push(i);
    }
    while (q.size())
    {
        auto t = q.front();
        q.pop();
        for (int i = 0; i < g[t].size(); i ++ )
        {
            int j = g[t][i];
            in[j] -- ;
            if (in[j] == 1) q.push(j);
        }
    }
    vector<int> huan;
    vector<int> st(n + 1);
    for (int i = 1; i <= n; i ++ )
    {
        if (in[i] > 1)
        {
            huan.push_back(i);
            st[i] = true;
        }
    }
    int ans = 0, sumtmp, sum = 0;
    vector<bool> visited(n + 1);
    function<void(int, int)> dfs = [&](int u, int fa)
    {
        sumtmp ++ ;
        if (visited[u]) return;
        visited[u] = true;
        for (int i = 0; i < g[u].size(); i ++ )
        {
            int j = g[u][i];
            if (j == fa || visited[j] || st[j]) continue;
            dfs(j, u);
        }
        return;
    };
    for (auto i : huan)
    {
        sumtmp = 0;
        dfs(i, -1);
        ans += sumtmp * (sumtmp - 1) / 2;
        ans += (sumtmp - 1) * (n - sumtmp - sum) * 2;
        sum += sumtmp - 1;
    }
    ans += huan.size() * (huan.size() - 1);
    cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t -- )
	{
		solve();
	}
}

AT ARC148A mod M

题目链接

受到之前cf有场div2的启发,当xy模mod余数相同,等价于x与y之差是mod的倍数

所以首先判断是否全为偶数,如果全是偶数直接除以2就可以

如果不是偶数,最差的情况是除以2,有的是1有的是0,然后再看一下能不能让所有数全部相同,我们就计算相邻两数之差取gcd,如果gcd是1就不能让所有数全相同,不是1直接除以那个gcd就可以让所有数全相同了

#include 

using namespace std;

typedef pair<int, int> PII;

#define int long long

void solve()
{
	int n;
	cin >> n;
	vector<int> a(n);
	int cnt0 = 0, cnt1 = 0;
	for (int i = 0; i < n; i ++ )
	{
		cin >> a[i];
		if (a[i] % 2 == 0 ) cnt0 ++ ;
		else cnt1 ++ ;
	}
	if (cnt0 == n) cout << 1 << '\n';
	else
	{
		sort(a.begin(), a.end());
		int tmp = a[1] - a[0];
		for (int i = 2; i < n; i ++ ) tmp = __gcd(tmp, a[i] - a[i - 1]);
		if (tmp == 1) cout << 2 << '\n';
		else cout << 1 << '\n';
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 1854B Earn or Unlock

题目链接

dp+bitset优化

如果我们可以到第 i 张牌,那我们得到的积分就是 a[1] + a[2] + … + a[i] - (i - 1),为什么是这么多呢,因为前面 i 张牌得到的积分是 a[1] 加到 a[i],然后我们为了到第 i 张,还需要花费 i - 1(第一张思免费送给我们的)

现在问题就变成了判断能否到 i 的位置,用bitset记录,如果可以到 i 的位置就把 dp[i] 赋为 1,到第 i 位就更新ans,要注意更新完之后要把 dp[i] 恢复成 0(因为有后效性,如果不清空,后面的操作就会把当前位的1往后挪)

#include 

using namespace std;

typedef pair<int, int> PII;

#define int long long

const int N = 200010;

void solve()
{
	int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i ++ ) cin >> a[i];
    bitset<N> dp;
    dp[0] = 1;
    n <<= 1;
    int sum = 0, ans = 0;
    for (int i = 0; i < n; i ++ )
    {
        if (i < n / 2)
        {
            dp |= (dp << a[i]);
            sum += a[i];
        }
        if (dp[i])
        {
            ans = max(ans, sum - i);
            dp[i] = 0;
        }
    }
    cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 1055A Metro

题目链接

用Dijkstra做的,dfs应该也可以

#include 

using namespace std;

typedef pair<int, int> PII;

void solve()
{
	int n, s;
	cin >> n >> s;
	vector<int> a(n + 1), b(n + 1);
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	for (int i = 1; i <= n; i ++ ) cin >> b[i];

	vector<vector<int>> g(n + 1);
	int last = -1;
	for (int i = 1; i <= n; i ++ )
	{
		if (a[i] == 1 && last != -1) g[last].push_back(i), last = i;
		else if (a[i] == 1) last = i; 
	}
	last = -1;
	for (int i = n; i > 0; i -- )
	{
		if (b[i] == 1 && last != -1) g[last].push_back(i), last = i;
		else if (b[i] == 1) last = i; 
	}
	priority_queue<PII, vector<PII>, greater<PII>> q;
	vector<int> dist(n + 1, 0x3f3f3f3f);
	dist[1] = 0;
	q.push(make_pair(0, 1));
	vector<bool> st(n + 1);
	while (q.size())
	{
		auto t = q.top();
		q.pop();
		int dd = t.first, ver = t.second;
		if (st[ver]) continue;
		st[ver] = true;
		for (int i = 0; i < g[ver].size(); i ++ )
		{
			int j = g[ver][i];
			if (dist[j] > dist[ver] + 1)
			{
				dist[j] = dist[ver] + 1;
				q.push(make_pair(dist[j], j));
				if (j == s)
				{
					cout << "YES\n";
					return;
				}
			}
		}
	}
	if (dist[s] == 0x3f3f3f3f) cout << "NO\n";
	else cout << "YES\n";
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	while (t -- )
	{
		solve();
	}
}

CF 460C Present

题目链接

二分+树状数组

#include 

using namespace std;

typedef pair<int, int> PII;

#define int long long

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

void solve()
{
	int n, m, w;
	cin >> n >> m >> w;
	vector<int> tr(n + 1), a(n + 1);
	int minn = 0x3f3f3f3f, maxx = 0;
	for (int i = 1; i <= n; i ++ )
	{
		cin >> a[i];
		maxx = max(maxx, a[i]);
		minn = min(minn, a[i]);
	}
	auto add = [&](int i, int x, vector<int> &tr)
	{
		for (; i <= n; i += lowbit(i))
			tr[i] += x;
	};
	for (int i = 1; i <= n; i ++ ) add(i, a[i] - a[i - 1], tr);

	vector<int> notav;
	auto presum = [&](int i, vector<int> &tmp)
	{
		int res = 0;
		for (; i > 0; i -= lowbit(i)) res += tmp[i];
		return res;
	};

	auto check = [&](int mid)
	{
		vector<int> tmp(tr);
		int cnt = 0;
		for (int i = 1; i <= n; i ++ )
		{
			if (presum(i, tmp) < mid)
			{
				if (cnt == m) return false;
				add(i, 1, tmp);
				add(i + w, -1, tmp);
				cnt ++ ;
				i -- ;
			}
		}
		return true;
	};
	
	int l = minn, r = 1e10;
	while (l < r)
	{
		int mid = l + r + 1 >> 1;
		if (check(mid)) l = mid;
		else r = mid - 1;
	}
	cout << r << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t -- )
	{
		solve();
	}
}

CF 894A QAQ

题目链接

大水题

#include 

using namespace std;

void solve()
{
	string s;
	cin >> s;
	int ans = 0;
	for (int i = 0; i < s.size(); i ++ )
	{
		if (s[i] == 'Q')
		{
			for (int j = i + 1; j < s.size(); j ++ )
			{
				if (s[j] == 'A')
				{
					for (int k = j + 1; k < s.size(); k ++ )
					{
						if (s[k] == 'Q')
						{
							ans ++ ;
							continue;
						}
					}
				}
			}
		}
	}
	cout << ans << '\n';
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	while (t -- )
	{
		solve();
	}
}

你可能感兴趣的:(2024寒假训练记录,算法)