[CF1097X]Hello 2019

Posted by Dispwnl on January 4, 2019

上紫纪念

A  Gennady and a Card Game

题目大意

每个元素有两个值$a,b$,现在你有$5$个元素,问是否有一个元素与给定元素$a$相等或者$b$相等

题解

代码

# include<bits/stdc++.h>
using namespace std;
int A,B;
int a[5],b[5];
char s[5][10],qwq[10];
int main()
{
	scanf("%s",qwq);
	A=qwq[0],B=qwq[1];
	for(int i=0;i<5;++i)
	  {
	  	scanf("%s",s[i]);
	  	a[i]=s[i][0],b[i]=s[i][1];
	  	if(a[i]==A||B==b[i]) return printf("YES\n"),0;
	  }
	return printf("NO\n"),0;
}

B  Petr and a Combination Lock

题目大意

给定$n$个角度$a_i$,初始在$0°$位置,第$i$次操作顺/逆时针旋转$a_i°$,问能否在$n$次旋转后回到$0°$的位置

题解

$n$最大才$15$,状态压缩一下表示即可

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
using namespace std;
int n;
int a[21];
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;++i)
	  scanf("%d",&a[i]);
	for(int i=0;i<(1<<n);++i)
	  {
	  	int ans=0;
	  	for(int j=0;j<n;++j)
	  	  if(i&(1<<j)) ans+=a[j];
	  	  else ans-=a[j];
	  	if(ans%360==0) return puts("YES"),0;
	  }
	return puts("NO"),0;
}

C  Yuhao and a Parenthesis

题目大意

给定$n$个括号序列(不一定合法),每次可以选择两个没选过的序列首尾相连合并成一个括号序列,问合并之后最多有多少个合法括号序列

题解

'('定为$1$,')'定为$-1$,可以记录每个括号序列的总和和最小前缀和,显然)...(这种是不可能组成合法的括号序列的,分总和$>0,=0,<0$三种情况讨论一下即可

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<map>
# include<algorithm>
using namespace std;
const int MAX=1e5+5;
int n,ans;
char a[MAX*5];
map<int,int> ma;
int main()
{
	scanf("%d",&n);
	for(int i=1,_n,w,_w;i<=n;++i)
	  {
	  	scanf("%s",a),_n=strlen(a),w=0,_w=1e9;
	  	for(int j=0;j<_n;++j)
	  	  {
	  	  	if(a[j]=='(') ++w;
	  		else --w;
	  		_w=min(_w,w); 
		  }
		if(!w&&_w>=0)
		{
			if(ma[w]) --ma[w],++ans;
			else ++ma[w];
		}
		if(w>0&&_w>=0)
		{
			if(ma[-w]) --ma[-w],++ans;
			else ++ma[w];
		}
		if(w<0&&_w>=w)
		{
			if(ma[-w]) --ma[-w],++ans;
			else ++ma[w];
		}
	  }
	return printf("%d",ans),0;
}

D  Makoto and a Blackboard

题目大意

给定两个数$n,k$,每次随机选择$n$的某个因子$a$使得$n=a$,问操作$k$次后$n$的期望值

题解

如果$n=p^m$($p$为素数)就可以直接暴力枚举$m$然后$dp$了

因为$n=p_1^{m_1}\times p_2^{m_2}\times…\times p_l^{m_l}$(对$n$质因子分解),所以答案为$\prod_{i=1}^{l} ans(p_i^{m_i})$,具体为什么不会证……听说好像是跟积性函数有关?管他呢A了就行了

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<cmath>
# include<map>
# include<algorithm>
# define LL long long 
using namespace std;
const int MAX=1e4+5,mod=1e9+7;
LL n;
int k,cnt,ans=1;
LL qwq[MAX];
int f[101][MAX];
map<LL,int> ma;
int Pow(LL a,int b)
{
	int ans=1;
	a%=mod;
	for(;b;b>>=1,a=1ll*a*a%mod)
	  if(b&1) ans=1ll*a*ans%mod;
	return ans;
}
int dfs(LL A,int x,int t=0)
{
	if(f[x][t]) return f[x][t];
	if(t==k) return Pow(A,x);
	int ans=0;
	for(int i=0;i<=x;++i)
	  ans=(ans+dfs(A,i,t+1))%mod;
	return f[x][t]=1ll*ans*Pow(x+1,mod-2)%mod;
}
int main()
{
	cin>>n>>k;
	for(int i=2;i<=sqrt(n);++i)
	  while(n%i==0)
	  {
	  	if(++ma[i]==1) qwq[++cnt]=i;
	  	n/=i;
	  }
	if(n!=1) if(++ma[n]==1) qwq[++cnt]=n;
	for(int i=1;i<=cnt;++i)
	  memset(f,0,sizeof(f)),ans=1ll*ans*dfs(qwq[i],ma[qwq[i]])%mod;
	return printf("%d",ans),0;
}

E  Egor and an RPG game

F  Alex and a TV Show

题目大意

给定$n$个初始为空的集合(可重集),有四个操作:

  • 给定集合位置$x$和一个数$v$,然后$S_x={v}$
  • 给定集合位置$x,y,z$,然后$S_x=S_y∪S_z$
  • 给定集合位置$x,y,z$,然后$S_x={\gcd(a,b)\vert a\in S_y,b\in S_z}$
  • 给定集合位置$x$和一个数$v$,然后输出集合$x$中有多少个$v$,答案$\%2$

题解

用$f_{x,i}$表示集合$S_x$中$i$的倍数出现次数的奇偶性,可以用bitset维护

因为值域才$7000$,操作一可以直接$\sqrt{n}$枚举修改

操作二发现都是$1$的时候答案是$0$,都是$0$的时候答案是$0$,一个是$0,1$的时候答案是$1$,所以就是一个异或操作

操作三发现都是$1$的时候答案是$1$,都是$0$的时候答案是$0$,一个是$0,1$的时候答案是$0$,所以就是一个与操作

操作四可以莫比乌斯反演一下:

设$F_{x,i}$表示集合$S_x$中$i$的出现次数,则有

$f_{x,i}=\sum_{i\vert j}F_{x,j}$

$F_{x,i}=\sum_{i\vert j}\mu(\frac{j}{i})f_{x,j}$

因为$f_{x,i}$只有$0/1$两种取值,所以$\mu$的值为$-1$和$1$没有区别,预处理一下即可

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<bitset>
# include<cmath> 
# include<algorithm>
using namespace std;
const int MAX=1e5+5,N=7e3+5;
int n,q,tot;
int u[N],pm[N];
bool use[N];
bitset<N> a[MAX],b[N],w[N];
int read()
{
	int x(0);
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x;
}
int main()
{
	n=read(),q=read(),u[1]=1;
	for(int i=2;i<N;++i)
	  {
	  	if(!use[i]) pm[++tot]=i,u[i]=-1;
	  	for(int j=1;j<=tot&&i*pm[j]<N;++j)
	  	  {
	  	  	use[i*pm[j]]=1;
	  	  	if(i%pm[j]==0) break;
	  	  	u[i*pm[j]]=-u[i];
		  }
	  }
	for(int i=1,x;i<N;++i)
	  {
	  	x=sqrt(i);
	  	for(int j=1;j<=x;++j)
	  	  if(i%j==0) w[i][j]=w[i][i/j]=1;
	  }
	for(int i=1;i<N;++i)
	  for(int j=i;j<N;j+=i)
	    if(u[j/i]) b[i][j]=1;
	for(int i=1,op,x,y,z;i<=q;++i)
	  {
	  	op=read(),x=read(),y=read();
	  	if(op==1) a[x]=w[y];
	  	else if(op==2) z=read(),a[x]=a[y]^a[z];
	  	else if(op==3) z=read(),a[x]=a[y]&a[z];
	  	else if(op==4) printf("%d",(a[x]&b[y]).count()%2);
	  }
	return 0;
}