A. Perfectly Imperfect Array
题解
只要任意一个数不是平方数就可以
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | #include<bits/stdc++.h>using namespace std;
 int const maxn=2e5+10;
 int main(){
 
 int t,n,a,v;
 cin>>t;
 while(t--){
 scanf("%d",&n);
 bool flag=false;
 for(int i=1;i<=n;i++){
 scanf("%d",&a);
 v=sqrt(a);
 if(v*v!=a)flag=true;
 }
 if(flag)printf("YES\n");
 else printf("NO\n");
 }
 return 0;
 }
 
 | 
B . AND 0, Sum Big
题意:
给你N和K, 问有多少长度为n的数组满足:
- 所有元素在[0,\(2^k-1\) ]范围内
- 所有元素AND值为0
- 所有元素之和尽可能大
题解:
快速幂:二进制k位,只要每一位有一个0就能满足条件2,为了满足条件3每一位只能在数组中的一个数中为0,所以每一位的选择有n个数,答案为\(n^k\)
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | #include<bits/stdc++.h>using namespace std;
 long long p=1e9+7;
 long long n,k,t;
 long long  pow_fast(long long  a,long long  b,long long  mod){
 long long  num=1%mod;
 for(;b;b>>=1,a=a*a%mod)
 if(b&1)num=num*a%mod;
 return num;
 }
 int main(){
 cin>>t;
 while(t--){
 scanf("%lld%lld",&n,&k);
 long long ans=pow_fast(n,k,p);
 printf("%lld\n",ans);
 }
 return 0;
 }
 
 | 
C . Product 1 Modulo N
题意:
给定n,问[1,n-1]范围内,最多可以取多少数,使其乘积取模n为1
数据范围:
\[\left( 2  \leq n \leq 10^{5}\right)\]
题解:
首先知道一个结论:如果a,b的最大公约数g=gcd(a,b)不为1,则a%b大于1,因为a%b的余数一定是g的倍数。
(1) a%b = (a/g) % (b/g) * g
所以只能选与n互质的数,他们的乘积取余n的结果x也与n互质,x就在刚刚所取的数中,只要把x删掉就行了
证明1: a%b = (a/g) % (b/g) * g


证明:2:与b互质的数乘积取余b的余数与b互质
设 \(a_1,a_2,a_3..a_m\) 与b互质 z=a_1a_2a_3 z=n*b+p g=gcd(n,p) n=cg , p=dg z=gcb+dg=g(cb+d) 则 g是 z 的因子,如果g ≠ 1,则n与 z不互质,与题设矛盾
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | #include<bits/stdc++.h>using namespace std;
 vector<int> v;
 int gcd(int a,int b)
 {
 return b?gcd(b,a%b):a;
 }
 int main(){
 int n;
 scanf("%d",&n);
 v.push_back(1);
 long long tmp=1;
 for (long long i=2;i<n;i++){
 if (gcd(i,n)==1){
 v.push_back(i);
 tmp=(1ll*tmp*i)%n;
 }
 }
 if (tmp==1ll) cout<<v.size()<<endl;
 else cout<<v.size()-1<<endl;
 for (long long i=0;i<v.size();i++){
 if (v[i]==tmp&&tmp!=1) continue;
 cout<<v[i]<<" ";
 }
 cout<<endl;
 }
 
 | 
网上看到的另一种不错证明,原文链接
不能选与n不互质的数, 因为选了之后%n一定不为1,因为gcd(乘积,n)!=1. 证明: 设gcd(p,n)=z,则p=xz,n=yz, 设选的其他数乘积为q, 则pq%n=1,设pq=kn+1, 那么qxz=kyz+1, (qx-ky)z=1, 当且仅当z=1时式子才有可能成立, 而gcd=z>1,因此式子不可能成立, 所以如果选择了gcd!=1的数,一定不满足条件.
因此只能选与n互质的数, 设s为所有与n互质的数的积对n取模的结果, 如果s=1,那么这些数全部可以选择, 如果s!=1,此时s一定与n互质,因此s也在这些数中, 那么选除了s的其他数就行了
D. Cut and Stick
题意:
给出长度为n的序列a,q个询问,每次询问[l,r]区间。
问至少把区间内的数重新组合成几段,才能满足每段众数的次数不超过 \(\left \lceil len \right \rceil\) , len为区间长度
数据范围:
\(\left( 1 \leq n,q \leq 3*10^{5}\right)\)
\(a_{1}, a_{2, \ldots,} a_{n}\left(1 \leq a_{i} \leq n\right)\)
\((1 \leq l \leq r \leq n)\)
题解:
- 如果初始区间众数个数< \(\left \lceil len \right \rceil\) , 则不用拆,答案为1。否则就要拆,关于每段如何拆分。
偶→奇+奇 ,可容纳数增加1;奇→偶+奇,可容纳数不变。于是每次就是尽量拆偶数,变化如下
初始偶→奇+奇→偶+奇+奇→奇+奇+奇+奇→偶+奇++奇+奇+奇...
初始奇→偶+奇→奇+奇+奇→偶+奇++奇+奇...
实际上就是初始为偶数多了一步,后面跟奇数一样拆法。每多1个,段数+2。
- 莫队求区间众数,时间复杂度n*sqrt(n)。开一个数组num记录每个数的个数,数组cou[x]记录数量为x的数有几个。
每次区间增加时,增加这个数的个数,维护cou。还有判断增加后是否变成区间众数
区间变小时,减少这个数的个数,维护cou。看当前众数个数值的cou是否变为0,如果变为0说明当前数为唯一众数,众数个数应该-1。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 
 | using namespace std;
 //
 int const MAXN = 3e5+7;
 int a[MAXN],unit,n,m,nowmax,cnt[MAXN],ans[MAXN],num[MAXN];
 struct query1{
 int L,R,id;
 }qu[MAXN];
 bool cmp(query1 a,query1 b){
 if(a.L/unit == b.L/unit)    //相同块,对R排序
 return a.R < b.R;
 else return a.L/unit <b.L/unit; //不同块,对块排序
 }
 void mo_add(int x){
 cnt[num[a[x]]]--;
 num[a[x]]++;
 cnt[num[a[x]]]++;
 if(num[a[x]]>nowmax)nowmax=num[a[x]];
 }
 void mo_del(int x){
 cnt[num[a[x]]]--;
 num[a[x]]--;
 cnt[num[a[x]]]++;
 if(cnt[nowmax]==0)nowmax--;
 }
 void work(){
 int L = 1,R = 0;
 for(int i=0;i<m;i++){
 while(R < qu[i].R){
 R++;
 mo_add(R);
 }
 while(R > qu[i].R){
 mo_del(R);
 R--;
 }
 while(L < qu[i].L){
 mo_del(L);
 L++;
 }
 while(L > qu[i].L){
 L--;
 mo_add(L);
 }
 // debug(nowmax,1);
 if(nowmax<=ceil((R-L+1)/2.0))ans[qu[i].id]=1;
 else{//奇偶不同拆法
 int z=1,len=R-L+1,u=nowmax-ceil((R-L+1)/2.0);
 if(len%2==0){z++;u--;}
 while(u){
 z+=2;u--;
 }
 ans[qu[i].id]=z;
 }
 }
 }
 
 int main(){
 scanf("%d%d",&n,&m);
 for(int i=1;i<=n;i++)scanf("%d",&a[i]);
 unit=sqrt(n);
 for(int i=0;i<m;i++){  //读入查询
 scanf("%d%d",&qu[i].L,&qu[i].R);
 qu[i].id = i;
 }
 sort(qu,qu+m,cmp);
 work();
 for(int i=0;i<m;i++){
 printf("%d\n",ans[i]);
 }
 return 0;
 }
 
 | 
比赛时:
想到了莫队,但是当莫队区间变小时卡住了,忘记了只要再维护一个众数的个数有多少就行了。