• 牛客练习赛27游记


    牛客练习赛27游记

    A - 纸牌

    题目大意:

    有两张纸牌,两张纸牌上有相同的正整数(n(nle10^9))
    每一轮一张纸牌上的数都可以减去小于等于另外一张纸牌上的数的非负数。
    每一轮只能操作和上轮不同的纸牌。
    求三轮之后两张纸牌上数字之和的最小值。

    思路:

    答案就是(lceilfrac n2 ceil)

    源代码:

    #include<cstdio>
    #include<cctype>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    int main() {
    	const int n=getint();
    	printf("%d
    ",n/2+n%2);
    	return 0;
    }
    

    B - 手办

    题目大意:

    给定(n(nle10^{12})),求(sum_{k=1}^nsum_{a=1}^ksum_{b=1}^k[ab|k])

    思路:

    题目就是要求满足(abcle n)的三元组((a,b,c))个数。

    (ale ble c),那么(a)枚举到(sqrt[3]n)(b)在剩下(sqrt{frac na})中枚举,(c)的个数可以直接算出来。

    交换(a,b,c)总共会有(6)种方案。

    另外注意判断(2)个数和(3)个数相同的情况。

    源代码:

    #include<cstdio>
    #include<cctype>
    typedef long long int64;
    inline int64 getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int64 x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int mod=2333;
    int main() {
    	const int64 n=getint();
    	int ans=0;
    	for(register int i=1;(int64)i*i*i<=n;i++) {
    		(ans+=1+(n/i/i-i)*3%mod)%=mod;
    		for(register int j=i+1;(int64)j*j<=n/i;j++) {
    			(ans+=3+(n/i/j-j)*6%mod)%=mod;
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    C - 水图

    题目大意:

    一棵(n(nle50000))个结点的带边权的树,求从(x)出发经过每个点至少一次最少需要走多少路。

    思路:

    所有边权和×2-从x出发能走最远的距离。

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=50001;
    typedef long long int64;
    int64 dep[N],max;
    struct Edge {
    	int to,w;
    };
    std::vector<Edge> e[N];
    inline void add_edge(const int &u,const int &v,const int &w) {
    	e[u].push_back((Edge){v,w});
    	e[v].push_back((Edge){u,w});
    }
    void dfs(const int &x,const int &par) {
    	for(auto &j:e[x]) {
    		const int &y=j.to,&w=j.w;
    		if(y==par) continue;
    		dep[y]=dep[x]+w;
    		dfs(y,x);
    	}
    	max=std::max(max,dep[x]);
    }
    int main() {
    	const int n=getint(),x=getint();
    	int64 ans=0;
    	for(register int i=1;i<n;i++) {
    		const int u=getint(),v=getint(),w=getint();
    		add_edge(u,v,w);
    		ans+=(int64)w*2;
    	}
    	dfs(x,0);
    	ans-=max;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    D - 愤怒

    题目大意:

    将一个长度为(n(nle10000))的序列划分为恰好两个子序列,使得两个子序列合法,求方案数。

    思路:

    左括号当成(1),右括号当(-1)(f_{i,j})表示考虑完前(i)个字符,第一个序列的前缀和是(j)的方案数。考虑下一个字符时,可以将其加入第一个序列和第二个序列。如果前缀和(<0)就不合法,否则就可以转移。

    时间复杂度(mathcal O(n^2))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    inline bool check(const char &ch) {
    	return ch=='('||ch==')';
    }
    inline int getval() {
    	register char ch;
    	while(!check(ch=getchar()));
    	if(ch=='(') return 1;
    	if(ch==')') return -1;
    	return 0;
    }
    const int N=10001,mod=2333;
    int f[2][N],sum[N];
    int main() {
    	const int n=getint();
    	f[0][0]=1;
    	for(register int i=1;i<=n;i++) {
    		const int cur=i&1;
    		const int x=getval();
    		sum[i]=sum[i-1]+x;
    		if(sum[i]<0) {
    			puts("0");
    			return 0;
    		}
    		memset(f[cur],0,sizeof f[cur]);
    		for(register int j=0;j<=n;j++) {
    			if(0<=j+x&&j+x<=n) {
    				(f[cur][j+x]+=f[!cur][j])%=mod;
    			}
    			if(sum[i]-j>=0) {
    				(f[cur][j]+=f[!cur][j])%=mod;
    			}
    		}
    	}
    	printf("%d
    ",f[n&1][0]);
    	return 0;
    }
    

    E - 欧拉

    题目大意:

    (m(mle5 imes10^5))次询问,每次给出(n(nle5 imes10^6)),求(F(n)=sum_{d|n}d^kmu(frac nd))。模(998244353)

    思路:

    (F(n))是一个积性函数,直接线性筛即可。

    源代码:

    #include<cstdio>
    #include<cctype>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    typedef long long int64;
    const int N=5e6+1,mod=998244353;
    int m,k;
    inline int power(int a,int k) {
    	int ret=1;
    	for(;k;k>>=1) {
    		if(k&1) ret=(int64)ret*a%mod;
    		a=(int64)a*a%mod;
    	}
    	return ret;
    }
    int p[N],f[N];
    bool vis[N];
    inline void sieve() {
    	for(register int i=2;i<N;i++) {
    		if(!vis[i]) {
    			p[++p[0]]=i;
    			f[i]=power(i,k)-1;
    		}
    		for(register int j=1;j<=p[0]&&i*p[j]<N;j++) {
    			vis[i*p[j]]=true;
    			f[i*p[j]]=(int64)f[i]*(f[p[j]]+!(i%p[j]))%mod;
    			if(i%p[j]==0) break;
    		}
    	}
    }
    int main() {
    	m=getint(),k=getint();
    	sieve();
    	for(register int i=0;i<m;i++) {
    		printf("%d
    ",f[getint()]);
    	}
    	return 0;
    }
    

    F - 计数

  • 相关阅读:
    Linux关闭防火墙命令
    js改变数组的两个元素的位子,互换、置顶
    vue nexttick的理解和使用场景
    vue mint-ui 框架下拉刷新上拉加载组件的使用
    vue项目中使用了vw适配方案,引入第三方ui框架mint-ui时,适配问题解决
    小程序开发笔记【二】,抽奖结果json数据拼装bug解决
    gulp插件gulp-nunjucks-render的使用及gulp4的简单了解
    小程序开发笔记【一】,查询用户参与活动列表 left join on的用法
    mysql数据插入前判断是否存在
    微信公众号通过图片选取接口上传到阿里oss
  • 原文地址:https://www.cnblogs.com/skylee03/p/9689347.html
Copyright © 2020-2023  润新知