codeforces Hello 2019

codeforces Hello 2019


Hello candidate master

然而没有紫,D题空间少开了1e6,fst了呜呜呜

新年第一场cf2333

感觉难度比 good bye 2018良心很多啊

T1

日常送分题,判断有没有相同的

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
char s[10],t[10]; 
int main(){
//	freopen("1.in","r",stdin);
	scanf("%s",s+1);
	for(int i=1;i<=5;i++){
		scanf("%s",t+1);
		if(s[1]==t[1]||s[2]==t[2]){
			printf("YES\n");
			return 0;
		}
	}
	printf("NO\n");
	return 0;
}

T2

日常送分题 x 2

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=20;
int n,a[maxn];
void dfs(int x,int y){
	if(x>n){
		if(y%360==0){
			printf("YES\n");
			exit(0);
		}
		return;
	}
	dfs(x+1,y+a[x]);
	dfs(x+1,y-a[x]);
}
int main(){
//	freopen("1.in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	dfs(1,0);
	printf("NO");
	return 0;
}

T3

。。。我去怎么三道sb题

对于每个括号序列,统计它左边和右边分别需要补几个,如果都要补就没法用,否则设补左边正,补右边负,开个\(map\)存一下取最小值就好了

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=5e5+100;
int n,b[maxn],num;
char s[maxn];
map<int,int>p;
map<int,bool>cz;
int main(){
//	freopen("1.in","r",stdin);
	//freopen(".out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		int len=strlen(s+1),l=0,r=0;
		for(int j=1;j<=len;j++)
			if(s[j]=='(') l++;
			else
				if(l) l--;
				else r++;
		if(l&&r) continue;
		int k;
		if(l) k=l;
		else k=-r;
		p[k]++;
		if(k<0&&!cz[k]) cz[k]=1,b[++num]=k;
	}
	int ans=0;
	for(int i=1;i<=num;i++)
		ans+=min(p[b[i]],p[-b[i]]);
	ans+=p[0]/2;
	printf("%d\n",ans);
	return 0;
}

T4

题意:一个数n,每次将自己等概率变为自己的一个约数,问变了K次后的n期望大小 (n<1e14 , k<1e4)

把n分解质因数,设\(n=p_1^{k_1}p_2^{k_2}...p_m^{k_m}\)

可以发现,每变一次,每个指数\(k_i\)都会等概率地变成\(0-k_i\)中的一个

那么我们对于每个质因数都求一下他的期望,然后全都乘起来应该就是最后的答案了

对于一个质因数\(p_i^{k_i}\),怎么算他的期望呢?

\(k_i\)变了\(j\)次变成\(x\)的概率为\(f[j][x]\),因为\(x\)一定是由一个大于等于\(x\)的数\(y\)\(1/(y+1)\)(有可能变成零,所以是\(y+1\))的概率变来的,所以

\[f[j][x]=\sum_{y=x}^{k_i}{f[j-1][y]*inv[y+1]} \]

当然,\(f[0][k_i]=1\)

\(f[n][i]\)都求出来了,那么这个质因数的期望就是\(\sum_{i=1}^{k_i}{f[n][i]*pow(p,i)}\)

然后这个\(dp\)可以用前缀和优化(\(y\)按照从\(k_i\)\(x\)来枚举)时间复杂度\(O(K*k_i)\)

\(n\)的质因数个数以及每个质因数的次数\(k_i\)都是\(logn\)级别的

所以总时间复杂度\(O(Klog ^2n)\)

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=3e7;
const ll P=1e9+7;
int p[maxn],num;
ll n,k,inv[10000],f[2][10000],b[10000],tot,c[10000]; 
bool vis[maxn];
void ycl(){
	int lim=3e7;
	for(int i=2;i<lim;i++){
		if(!vis[i])
			p[++num]=i;
		for(int j=1;1ll*p[j]*i<lim;j++){
			vis[p[j]*i]=1;
			if(i%p[j]==0) break;
		}
	}
	inv[0]=inv[1]=1;  
    for(int i=2;i<=1000;i++)
        inv[i]=(1ll*(P-P/i)*inv[P%i])%P; 
}
inline ll poww(ll x,ll y){
	ll base=1;
	while(y){
		if(y&1) base=base*x%P;
		x=x*x%P;
		y>>=1;
	}
	return base;
}
ll work(ll x,int y){
	for(int i=0;i<=y;i++) f[0][i]=0;
	int nw=0;f[0][y]=1;
	for(int i=1;i<=k;i++){
		nw^=1;
		ll siz=0;
		for(int j=y;j>=0;j--){
			siz+=f[nw^1][j]*inv[j+1]%P,siz%=P;
			f[nw][j]=siz;
		}
	}
	ll siz=0;
	for(int i=0;i<=y;i++)
		siz+=poww(x,i)*f[nw][i]%P,siz%=P;
	siz%=P; 
	return siz;
}
int main(){
//	freopen("1.in","r",stdin);
	//freopen(".out","w",stdout);
	ycl();
	scanf("%I64d%I64d",&n,&k);
	for(int i=1;i<=num&&p[i]<=n;i++)
		if(n%p[i]==0){
			b[++tot]=p[i];
			while(n%p[i]==0) n/=p[i],c[tot]++;
		}
	ll ans=1;
	for(int i=1;i<=tot;i++)
		ans=ans*work(b[i],c[i])%P;
	if(n!=1) ans=ans*work(n,1)%P;
	printf("%I64d\n",(ans%P+P)%P);
	return 0;
}
posted @ 2019-01-05 01:47  nianheng  阅读(306)  评论(2编辑  收藏  举报