題目鏈接
被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;
}