Codeforces Round #774 (Div. 2) - E. Power Board

枚举 + 数论

Problem - E - Codeforces

题意

有一个 \(n*m\;(1<=n,m<=10^6)\) 的矩阵,第 i 行第 j 列是 \(i^j\), 求这个矩阵中的 \(n*m\) 的数中有多少种不同的数

思路

  1. 第 1 行都是 1;

  2. 和第 2 行 有可能 重复的只可能在 2 的幂次行;

    和第 3 行 有可能 重复的只可能在 3 的幂次行;

    第 4 行在 2 的幂次行中;

    和第 5 行 有可能 重复的只可能在 5 的幂次行;

    和第 6 行 有可能 重复的只可能在 6 的幂次行;

    ...

  3. 因此对于每个底数 \(t\), 只要只要知道 \(t\) 最多有 \(k\) 个幂次行,就可以知道当前的底数控制的这些行中有多少不同的数

    这个底数 \(t\) 对答案的贡献只与 \(k\) 有关,与 \(t\) 是多少无关(因为底数是一样的,只要指数一样就行)

    1 2 3 4 5
    2 2^1 2^2 2^3 2^4 2^5
    4 2^(2*1) 2^(2*2) 2^(2*3) 2^(2*4) 2^(2*5)
    8 2^(3*1) 2^(3*2) 2^(3*3) 2^(3*4) 2^(3*5)
  4. 可以预处理出当某个底数有 \(k\) 个幂次行时,有多少不同的数

    //mp[i]表示有当前的底数有i个幂次行时,这i个幂次行在当前底数下,一共有mp[i]个不同的指数
    //M = 22 表示即使底数是2,也最多有 20 个幂次行
    void presolve()
    {
    	for (int i = 1; i < M; i++)
    	{
    		for (int j = 1; j <= m; j++)
    		{
    			if (!st[i * j])
    			{
    				cnt++;
    				st[i * j] = true;
    			}
    		}
    		mp[i] = cnt;
    	}
    }
    

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 1e6 + 10, M = 22;
int n, m;
int mp[M];//mp[i]表示有当前的底数有i个幂次行时,这i个幂次行在当前底数下,一共有mp[i]个不同的指数
int cnt;
bool st[N * M], vis[N];

void presolve()
{
	for (int i = 1; i < M; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (!st[i * j])
			{
				cnt++;
				st[i * j] = true;
			}
		}
		mp[i] = cnt;
	}
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	presolve();
	ll ans = 1;
	for (int i = 2; i <= n; i++)
	{
		if (vis[i])
			continue;
		int j = 0;
		ll now = i;
		while(now <= n)
		{
			vis[now] = true;
			now *= i;
			j++;
		}
		ans += mp[j];
	}
	cout << ans << endl;
    return 0;
}
posted @ 2022-10-05 12:53  hzy0227  阅读(25)  评论(0编辑  收藏  举报