题目链接
被C题卡到了,最后打表出的。。。D赛后补的。
A题
题意:
给你n个数的序列吗,问你是否存在子序列的乘积不是一个平方数
思路:
分解质因数,判断有没有是奇数个的质因子就行。
int n, c;
map<int, int> mp;
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
mp.clear();
cin >> n;
bool flag = true;
while(n --)
{
int x;
cin >> x;
for(int i = 2 ; i * i <= x ; i ++)
{
while(x % i == 0)
{
x /= i;
mp[i] ++;
}
}
if(x > 1) mp[x] ++;
for(auto x : mp)
if(x.y & 1)
flag = false;
}
if(!flag) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
B题
题意:
给你n和k,让你构造一个n个数的序列,使其满足下列条件,问你能构造出多少种序列
思路:
由于要数尽可能大,因此肯定所有数的所有二进制位上有且只有k个0,而且分别在不同权重的位上才满足,剩下的问题就是看每个k有多少种放法了。
显然每个k的放法都是互不相干的,因此总放法为\(n^k\)
int n, k;
int main()
{
IOS;
int T;
cin >> T;
while(T --)
{
cin >> n >> k;
ll res = 1;
for(int i = 1 ; i <= k ; i ++)
res = res * n % mod;
cout << res << endl;
}
return 0;
}
C题
题意:
给你n,让你从1到n - 1的所有数中,找出最多个数,使得它们的乘积模n余1.
思路:
我是打表做的。。。据说某个巨巨现场证明了
小于n的数 与其互质数的乘积 %n == 1 / n-1
总之,就是所有和n互质的数乘起来,如果最后乘积 % n != 1,去掉最后一项(一定是 n - 1)即可。
vector<int> res;
int n, d;
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
IOS;
cin >> n;
res.push_back(1);
ll sum = 1;
for(int i = 2 ; i <= n - 1 ; i ++)
{
if(gcd(i, n) == 1)
{
res.push_back(i);
sum = sum * i % n;
}
}
if(sum % n != 1) res.pop_back();
cout << res.size() << endl;
for(auto x : res)
cout << x << " ";
cout << endl;
return 0;
}
D题
莫队算法维护区间众数。
题意:
每次询问一个区间,将这个区间尽可能少的划分为几个子区间是的出现次数最多的那个数字不超过limit
limit = len/2(上取整,len为区间长度)
思路:
用莫队算法维护区间众数,即可快速实现查询。
然后每次需要将当前区间拆成多少子区间呢?
假设当前出现最多的数出现的次数是x,区间长度是len,那么需要将区间拆分成2*x - len个子序列。
图片来源:参考此处
int cnt[N], w[N];
struct Query{
int id, l, r;
}q[N];
int n, m, len;
int ans[N];
int tim[N]; //tim[i] 记录出现次数为 i 的数的个数
int get(int x)
{
return x / len;
}
bool comp(const Query &x, const Query &y)
{
int i = get(x.l), j = get(y.l);
if(i != j) return i < j;
return x.r < y.r;
}
void add(int x, int &res)
{
tim[cnt[x]] --;
cnt[x] ++;
tim[cnt[x]] ++;
res = max(res, cnt[x]);
}
void del(int x, int &res)
{
tim[cnt[x]] --;
if(tim[cnt[x]] == 0 && cnt[x] == res) res --;
cnt[x] --;
tim[cnt[x]] ++;
}
int main()
{
IOS;
cin >> n >> m;
for(int i = 1 ; i <= n ; i ++) cin >> w[i];
len = sqrt((double)n * n / m);
for(int i = 0 ; i < m ; i ++)
{
int l, r;
cin >> l >> r;
q[i] = {i, l, r};
}
sort(q, q + m, comp);
for(int k = 0 , i = 0, j = 1, res = 0 ; k < m ; k ++)
{
int id = q[k].id, l = q[k].l, r = q[k].r;
while(i < r) add(w[++ i], res);
while(i > r) del(w[i --], res);
while(j < l) del(w[j ++], res);
while(j > l) add(w[-- j], res);
ans[id] = res * 2 - (r - l + 1);
}
for(int i = 0 ; i < m ; i ++)
cout << max(1, ans[i]) << "\n";
return 0;
}