Codeforces Round#716 Div.2 Editorial
这套题,应该说 \(T3\) 很具有技术含量,卡了我将近三刻钟,后面心态有点崩,最后一道就没时间了。
T1 Array and Peaks ¶
只要存在一个不是完全平方数的数,就可以了。
inline int check(int x){
int tmp=sqrt(x*1.0);
if(tmp*tmp==x) return 1;
return 0;
}
signed main(){
int T=readin(1), n;
while(T--){
n=readin(1);
int flg=0, a;
for(int i=1; i<=n; ++i){
a=readin(1);
if(!check(a)) flg=1;
}
if(flg) printf("YES\n");
else printf("NO\n");
}
return 0;
}
T2 AND 0, Sum Big ¶
要让和最大,同时所有数字的按位与为 \(0\),对于每一位来说,只有可能是某一个数的这一位为 \(0\),其他数字都为 \(1\),对于一位有 \(n\) 个选择,一共 \(k\) 位,所以答案就是 \(n^k\bmod{10^9+7}\).
const int mod=1e9+7;
inline int qkpow(int a, int n){
int ret=1;
for(; n>0; n>>=1, a=1ll*a*a%mod)
if(n&1) ret=1ll*ret*a%mod;
return ret;
}
int n, k;
signed main(){
int T=readin(1);
while(T--){
n=readin(1), k=readin(1);
printf("%d\n", qkpow(n, k));
}
return 0;
}
T3 Product 1 Modulo N ¶
这道题卡了我好久,最后玄学猜了两个性质过掉了......
设我们最后选出来的数为 \(a_1,a_2,...,a_k\),若 \(A\overset{\Delta}{=}\prod_{i=1}^ka_i\),那么,由辗转相除法可得
即 \(A\) 实际上与 \(n\) 互质。那么这个就好办了,我们只需要将所有与 \(n\) 互质的数选上,如果我们记 \(M=\prod_{i=1}^{n-1}[\gcd(i,n)=1]i\),发现仍然有可能出现 \(M\not\equiv 1\pmod n\),记 \(M\equiv k\pmod n\),仍然考虑辗转相除法,有 \(1=\gcd(M,n)=\gcd(M\bmod n,n)=\gcd(k,n)\),发现 \(k\) 与 \(n\) 互质,并且 \(k<n\),说明这个余数只有一个,并且在 \([1,n-1]\) 之间,我们将它找出来就可以了。
#define Endl putchar('\n')
const int maxn=1e5;
int n;
int yes[maxn+5];
int gcd(int a, int b){
return !b? a: gcd(b, a%b);
}
signed main(){
n=readin(1);
int mul=1, cnt=0;
for(int i=1; i<=n; ++i)
if(gcd(i, n)==1){
mul=1ll*mul*i%n;
yes[i]=1, ++cnt;
}
if(mul!=1){
for(int i=1; i<=n; ++i) if(yes[i] && mul==i){
yes[i]=0;
--cnt;
}
}
printf("%d\n", cnt);
for(int i=1; i<=n; ++i) if(yes[i])
printf("%d ", i);
Endl;
return 0;
}
T4 Cut and Stick ¶
划分的区间长度之和为 \(n\),毋庸置疑地。对于多出来的数字,肯定的,如果有不满足的数字,那么只有可能有一个数字不满足。
设这个数字为纯种,剩下的为杂种,那么我们要用杂种去中和纯种。
考虑使用以下办法:
由于是上取整,那么显然,\(k\) 个杂种可以中和 \(k+1\) 个纯种。
那么现在有个问题了:对于一个区间 \([l,r]\),如果纯种数量为 \(t\),那么杂种数量即为 \(r-l+1-t\),问题在于如何才能用更少的区间去中和纯种;
设每次使用的杂种数量为 \(a_k\),那么一定有:
现在的问题就变成了如何求得一个区间的最多出现次数的数字了,看上去好像只能用分块,但是稍微对这道题性质分析一下可知,我们只需要求一个区间中是否有出现次数超过 \(\lceil {k\over 2}\rceil\),存在需要求出次数,由于这样的数字在一个区间中最多只会存在一个,所以我们可以考虑使用主席树,时间复杂度 \(\mathcal O(n\log n)\).
听说还可以使用随机化算法?那我就不知道了。
使用莫队可以达到 \(\mathcal O(n\sqrt n)\),并且不需要依赖这道题的特性,这很好,写一下:
\(\tt add()\) 就是一边加一边取 \(\max\),但是 \(\tt del()\) 就有点不一样了。
但是每次 \(\tt del()\) 之后,众数要么不变,要么减一,针对这个特性,我们再维护次数的出现次数即可。
const int maxn=3e5;
const int logn=20;
struct node{
int ls, rs, w;
node(){}
node(int L, int R, int W): ls(L), rs(R), w(W){}
}tre[maxn*logn+5];
int rt[maxn+5], ncnt;
#define mid ((l+r)>>1)
#define _lq tre[i].ls, l, mid
#define _rq tre[i].rs, mid+1, r
void modify(int p, int& i, int l, int r){
tre[++ncnt]=tre[i];
i=ncnt, ++tre[i].w;
if(l==r) return;
if(p<=mid) modify(p, _lq);
else modify(p, _rq);
}
int query(int w, int x, int y, int l, int r){
if(l==r) return tre[y].w-tre[x].w;
int lx=tre[tre[y].ls].w-tre[tre[x].ls].w;
if(lx>=w) return query(w, tre[x].ls, tre[y].ls, l, mid);
else return query(w, tre[x].rs, tre[y].rs, mid+1, r);
}
#undef mid
#undef _lq
#undef _rq
int a[maxn+5], n, q;
int cnt[maxn+5];
inline void input(){
n=readin(1), q=readin(1);
for(int i=1; i<=n; ++i)
a[i]=readin(1);
}
inline void getquery(){
int l, r;
while(q--){
l=readin(1), r=readin(1);
int tmp=query((r-l+2)>>1, rt[l-1], rt[r], 1, n);
int len=r-l+1;
if(tmp<=((len+1)>>1)) printf("1\n");
else printf("%d\n", 2*tmp-len);
}
}
signed main(){
input();
for(int i=1; i<=n; ++i)
modify(a[i], rt[i]=rt[i-1], 1, n);
getquery();
return 0;
}
T5 Baby Ehab's Hyper Apartment ¶
题读错+没时间......真真的雪上加霜啊。
题目让我们最后求每个点的联通性。