Codeforces Round #473 (Div. 2)
又是只\(A\)了四题...\(\rm E,F\)都很水但是开\(\rm vp\)的时候脑子抽掉了一直在想\(\rm F\)的\(\rm fwt\)做法就没时间了....
Codeforces Round #473 (Div. 2)
比赛链接:https://codeforc.es/contest/959
题目链接就不放了 才不是因为懒
A. Mahmoud and Ehab and the even-odd game
一步的博弈题...奇偶判断题。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
#define ll long long
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
ll ans,s;
int n,a[maxn];
signed main() {
read(n);
if(n&1) puts("Ehab");
else puts("Mahmoud");
return 0;
}
B. Mahmoud and Ehab and the message
并查集+哈希,考知识点的普及组题。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
#define ll long long
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
#define ull unsigned ll
char s[maxn];
int n,a[maxn],tot,fa[maxn],val[maxn],k,m,ans;
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
map<ull,int > h;
signed main() {
read(n),read(k),read(m);
for(int i=1;i<=n;i++) {
scanf("%s",s+1);int x=strlen(s+1);ull r=0;
for(int j=1;j<=x;j++) r=r*31+s[j];
h[r]=++tot;
}
for(int i=1;i<=n;i++) read(val[i]),fa[i]=i;
for(int i=1;i<=k;i++) {
int r,x,y;read(r);read(x);
for(int j=2;j<=r;j++) {
read(y);int u=find(y),v=find(x);
if(u!=v) fa[u]=v,val[v]=min(val[v],val[u]);
val[v]=min(val[v],val[y]);
}
}
for(int i=1;i<=m;i++) {
scanf("%s",s+1);int x=strlen(s+1);ull r=0;
for(int j=1;j<=x;j++) r=r*31+s[j];
ans+=val[find(h[r])];
}write(ans);
return 0;
}
C. Mahmoud and Ehab and the wrong algorithm
简单的构造题,错误就是两个菊花图连起来,正确的就是一个菊花图。
错误的\(n\leqslant 5\)时无解。
具体来说错误的情况就是以\(1\)为根和以\(2\)为根分别构造菊花图,然后连接\((1,2)\),正确答案为\(2\)但是他的算法会得到两个菊花图点数的最小值。图我就懒得画了
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
#define ll long long
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
#define ull unsigned ll
int n,tot;
signed main() {
read(n);
if(n<=5) puts("-1");
else {
int x=((n-1)>>1)+!(n&1);tot=1;
for(int i=1;i<=x;i++) printf("1 %d\n",++tot);
for(int i=x+1;i<n;i++) printf("2 %d\n",++tot);
}
for(int i=2;i<=n;i++) printf("1 %d\n",i);
return 0;
}
D. Mahmoud and Ehab and another array construction task
有点意思的贪心题。
答案显然是要尽可能的贴着给出的数列,那么我们先暴力的找到第一个和前面不互质的数,记起来,这一步可以分解质因数,\(O(n\log n)\)。
然后我们暴力的把这个数不停的\(+1\)直到和前面的互质,这一步因为至多加到前面没出现的最小的质数,所以也是\(O(n\log n)\)的,到这一步都可以保证正确性。
后面我们贪心的从小到大选择没出现过的质数,这样一定最优,因为如果你选一个合数,那么显然是没有把它拆成若干个质数仍前面优。
总复杂度\(O(n\log n)\)。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
#define ll long long
void print(ll x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int N = 4e6;
#define ull unsigned ll
int n,a[maxn],vis[N+10],pri[N+10],use[N+10],mn[N+10],tot,cnt;
void sieve() {
for(int i=2;i<=N;i++) {
if(!vis[i]) pri[++tot]=i,mn[i]=i;
for(int j=1;j<=tot&&i*pri[j]<=N;j++) {
mn[i*pri[j]]=pri[j];
vis[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
}
int check(int x,int t) {
while(x!=1) {
if(t) use[mn[x]]=1;
else if(use[mn[x]]) return 0;
x/=mn[x];
}return 1;
}
signed main() {
read(n);for(int i=1;i<=n;i++) read(a[i]);
sieve();int bo=0;cnt=1;
for(int i=1;i<=n;i++) {
if(bo) {
while(use[pri[cnt]]) {
cnt++;
}
a[i]=pri[cnt];cnt++;
} else if(check(a[i],0)) check(a[i],1);
else {
for(int k=a[i]+1;;k++)
if(check(k,0))
{check(k,1),a[i]=k,bo=1;break;}
}
}
for(int i=1;i<=n;i++) printf("%d ",a[i]);puts("");
return 0;
}
E. Mahmoud and Ehab and the xor-MST
这是本场最有意思的题了...
考虑手玩\(\rm kruskal\)的过程,可以发现每次都只有\(2\)的幂会造成贡献。
具体的来说,第一次\(2^0=1\)会造成贡献,会把\(n\)个点两两分成若干个连通块,分别是\((0,1),(2,3)\cdots\),那么我们可以把这\(n\)个点看成\(\lceil\frac{n}{2}\rceil\)个点。
第二次\(2^1=2\)会把这\(\lceil\frac{n}{2}\rceil\)个点又两两分组,连边方式为\((0,2),(4,6),(8,10)\cdots\)。
那么代码只要模拟这个过程就好了,复杂度\(O(\log n)\)。
顺便说一下这个数列在\(\rm OEIS\)上有:http://oeis.org/A006520
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define ll long long
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;
int n,ans;
signed main() {
read(n);
for(int i=1;i<n;i<<=1) ans+=i*((n/i+(n%i!=0))>>1);
write(ans);
return 0;
}
F. Mahmoud and Ehab and yet another xor task
我居然没想到线性基.......可能是太久没用过了把。
离线之后前缀线性基就好了,假设我们当前处理到\([1,p]\),现在的数为\(x\)。
那么如果线性基不能表示\(x\)显然无解,否则注意到线性基可以表示\([1,p]\)的每一个数,那么线性基也一定可以表示除了线性基之外所有数列中的数任意选若干个之后异或\(x\)的结果。
那么答案就是线性基之外的数任意选的方案数,也就是\(2^{p-sz}\),其中\(sz\)为线性基的大小。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
#define lf double
#define ll long long
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 2e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;
int n,T,a[maxn],sz,r[30],pw[maxn];
struct Q {int p,x,id,ans;}q[maxn];
int cmp1(Q a,Q b) {return a.p<b.p;}
int cmp2(Q a,Q b) {return a.id<b.id;}
void ins(int x) {
for(int i=20;~i;i--) {
if(!(x&(1<<i))) continue;
if(r[i]) x^=r[i];
else return sz++,r[i]=x,void();
}
}
int query(int x) {
for(int i=20;~i;i--) {
if(!(x&(1<<i))) continue;
if(r[i]) x^=r[i];
else return 0;
}return 1;
}
int main() {
read(n),read(T);FOR(i,1,n) read(a[i]);
FOR(i,1,T) read(q[i].p),read(q[i].x),q[i].id=i;
int t=1;pw[0]=1;sort(q+1,q+T+1,cmp1);
for(int i=1;i<=n;i++) {
ins(a[i]);pw[i]=pw[i-1]*2%mod;
while(q[t].p==i) {
if(query(q[t].x)) q[t].ans=pw[i-sz];
else q[t].ans=0;t++;
}
}sort(q+1,q+T+1,cmp2);
FOR(i,1,T) write(q[i].ans);
return 0;
}