2022第十三届蓝桥杯省赛A组C++游记

A组,当然是 很 蓝 的 啦

答案是n*m+3,无法节省步数

先手必败

无论先手怎么下,必定可以转化为

xxxo

oooo

然后,如果先手下第一行,后手就可以下第二行中间两个

xxxx

oxxo

必败

如果先手下第二行,则后手必定可以把第二行转化为oxxx或xxxo

xxxo 或 xxxo

oxxx xxxo

必败

有种不好的预感啊,“必败”

 水,代码:

#include<cstdio>
#define LL long long
int main()
{
	LL sum=0,sum2=0;
	int n,i,x;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&x);
		sum=sum+1ll*x;
		sum2=sum2+1ll*x*x;
	}
	printf("%lld",(sum*sum-sum2)/2);
	return 0;
}

 有点懵了

想到了可持久化01Trie树

突然发现可以离线

于是就写了莫队

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define D 320
struct node{
	int l,r,id;
	bool operator < (const node &t)const{
		return l/D<t.l/D||(l/D==t.l/D&&r<t.r);
	}
}q[N];
int a[N],tong[(1<<20)+5];
bool res[N];
int main()
{
	int n,m,x,i,l,r;
	n=gi();m=gi();x=gi();
	for(i=1;i<=n;i++)
		a[i]=gi();
	for(i=1;i<=m;i++){
		q[i].l=gi();
		q[i].r=gi();
		q[i].id=i;
	}
	sort(q+1,q+m+1);
	l=1;r=0;
	long long ans=0;
	for(i=1;i<=m;i++){
		while(r<q[i].r){
			r++;
			ans+=1ll*tong[a[r]];
			tong[a[r]^x]++;
		}
		while(l>q[i].l){
			l--;
			ans+=1ll*tong[a[l]];
			tong[a[l]^x]++;
		}
		while(r>q[i].r){
			tong[a[r]^x]--;
			ans-=1ll*tong[a[r]];
			r--;
		}
		while(l<q[i].l){
			tong[a[l]^x]--;
			ans-=1ll*tong[a[l]];
			l++;
		}
		if(ans>0)res[q[i].id]=1;
	}
	for(i=1;i<=m;i++)
		if(res[i])printf("yes\n");
		else printf("no\n");
	return 0;
}

 完了完了,概率期望我最菜

欸,好像还挺可做的

设f[i]为从i走到n的期望步数

于是可以列出方程f[i]=f[i+1]*(1-p[i+1])+f[0]*p[i+1]+1

然后f[n]=0

迭代带入之后,可以得到f[0]=A*f[0]+B

移项除一下就完事了

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=998244353;
int ksm(int x,int y)
{
	int ret=1;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		y>>=1;x=1ll*x*x%mod;
	}
	return ret;
}
#define N 100005
int p[N];
int main()
{
	int n,x,y,i;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d",&x,&y);
		p[i]=1ll*x*ksm(y,mod-2)%mod;
	}
	int a=p[n],b=1;
	for(i=n-1;i>=1;i--){
		a=1ll*a*(1ll-p[i]+mod)%mod;
		b=1ll*b*(1ll-p[i]+mod)%mod;
		a=(a+p[i])%mod;
		b=(b+1)%mod;
	}
	a=(1-a+mod)%mod;
	printf("%d",1ll*b*ksm(a,mod-2)%mod);
}

 这个真的不太会了(2333

首先,正着走和倒着走是一样的

其次,我们可以把2x次,看成一次性走2x只青蛙

二分答案是显然的

但是怎么验证呢?可以考虑,对于任意两个石头i,i+1之间的空隙

 从区间[i-Y+1,i]中,所有青蛙必须有落脚点,所以,任意长度为y的范围中的石头都需要满足

H之和大于等于2x

但是这只是必要条件,所以我猜这是充要条件

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL a[100005];
int main()
{
	int n,x,i,l,r,mid;
	scanf("%d%d",&n,&x);x*=2;
	a[1]=x;
	for(i=2;i<=n;i++){
		scanf("%lld",&a[i]);
		a[i]+=a[i-1];
	}
	l=1;r=n;
	while(l<r){
		mid=(l+r)>>1;
		bool flg=0;
		for(i=1;i<=n;i++){
			if(1ll*x>a[i]-a[max(i-mid,0)]){
				flg=1;
				break;
			}
		}
		if(flg) l=mid+1;
		else r=mid;
	}
	printf("%d",l);
}

 

 没思维含量,直接主席树吧

完了,不会写

突然发现可以在反向DP的时候顺带查询答案

所以用树状数组就够了

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define M 1000000
#define LOG 21
int a[N],f[N],g[N];
int tre[M+50];
void update(int x,int k)
{
	while(x<=M){
		tre[x]=max(tre[x],k);
		x+=(x&-x);
	}
}
int getmax(int x)
{
	int ans=0;
	while(x){
		ans=max(ans,tre[x]);
		x-=(x&-x);
	}
	return ans;
}
int n,K;
int main()
{
	int i;
	n=gi();K=gi();
	for(i=1;i<=n;i++)
		a[i]=gi();
	for(i=1;i<=n;i++){
		f[i]=getmax(a[i])+1;
		update(a[i],f[i]);
	}
	memset(tre,0,sizeof(tre));
	int ans=f[n-K]+K;
	for(i=n;i>=K+1;i--){
		g[i]=getmax(M-a[i]+1)+1;
		update(M-a[i]+1,g[i]);
		ans=max(ans,f[i-K-1]+K+getmax(M-a[i-K-1]+1));
	}
	printf("%d",ans);
}

 

 恶心大模拟

不想写,最后还是写了

先按长度排序

再把L范围内的点插入set中,按极角坐标排序

然后依次扫描即可

一堆细节和特判,估计还会卡精度

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
const double eps=1e-9;
const double PI=3.14159265358979;
inline double geta(double x,double y)
{
	if(fabs(x)<eps){
		if(y>=-eps) return 0;
		else return PI;
	}
	if(x>=eps) return PI/2-atan2(y,x);
	else return PI+PI/2-atan2(y,x);
}
struct node{
	double x,y,z;
	int id;
	bool operator < (const node &t)const{
		return geta(x,y)<geta(t.x,t.y);
	}
}a[N],now;
set<node> S;
set<node>::iterator it;
bool cmp(node &a,node &b)
{
	return 1ll*a.x*a.x+1ll*a.y*a.y<1ll*b.x*b.x+1ll*b.y*b.y;
}
int ans[N];
int main()
{
	int n,i,j;double L;
	n=gi();L=gi();
	for(i=1;i<=n;i++){
		a[i].x=gi();
		a[i].y=gi();
		a[i].z=gi();
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	now.x=0.0;now.y=L;
	for(i=1,j=1;i<=n;){
		while(j<=n&&sqrt(a[j].x*a[j].x+a[j].y*a[j].y)<=L){
			S.insert(a[j]);
			j++;
		}
		int o=i;
		it=S.lower_bound(now);
		if(it==S.end()){
			now.x=0.0;now.y=L;
			it=S.lower_bound(now);
			if(it==S.end())
				break;
		}
		node tmp=(*it);
		double tmpL=sqrt(tmp.x*tmp.x+tmp.y*tmp.y);
		tmp.x/=tmpL;tmp.y/=tmpL;
		
		ans[(*it).id]=o;i++;
		L+=tmp.z;
		now.x=tmp.x*L;now.y=tmp.y*L;
		S.erase(it);
		while(j<=n&&sqrt(a[j].x*a[j].x+a[j].y*a[j].y)<=L){
			S.insert(a[j]);
			j++;
		}
		bool flg;
		do{
			flg=0;
			
			it=S.lower_bound(now);
			node tmp2=(*it);
			if(it==S.end()){
				now.x=0.0;now.y=L;
				it=S.lower_bound(now);
				if(it==S.end())
					break;
			}
			double tmpL=sqrt(tmp2.x*tmp2.x+tmp2.y*tmp2.y);
			tmp2.x/=tmpL;tmp2.y/=tmpL;
			if(fabs(tmp2.x-tmp.x)<eps&&fabs(tmp2.y-tmp.y)<eps){
				ans[(*it).id]=o;i++;
				L+=tmp2.z;
				now.x=tmp2.x*L;now.y=tmp2.y*L;
				S.erase(it);
				while(j<=n&&sqrt(a[j].x*a[j].x+a[j].y*a[j].y)<=L){
					S.insert(a[j]);
					j++;
				}
				flg=1;
			}
		}while(flg);
	}
	for(i=1;i<=n;i++)
		if(!ans[i])ans[i]=-1;
	printf("%d",ans[1]);
	for(i=2;i<=n;i++)
		printf(" %d",ans[i]);
}

 

一眼Pollar_Rho,但是不会写

想了很多方法,联想到了当年学powerful_number的时候

全忘了

时间只剩十分钟了

打个10分暴力走人

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
int a[105],p[105],pcnt;
int tong[100];
int main()
{
	int T,n,i,j;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		pcnt=0;
		for(i=2;i<=int(sqrt(1.0*n)+0.5);i++){
			if(n%i==0){
				a[++pcnt]=i;
				do{p[pcnt]++;n/=i;}while(n%i==0);
			}
		}
		if(n!=1)
			printf("no\n");
		else{
			memset(tong,0,sizeof(tong));
			int cnt=0;
			for(i=pcnt;i>=1;i--){
				if(!tong[p[i]]){
					for(j=p[i];j<=100;j+=p[i])
						tong[j]=1;
					cnt++;
				}
			}
			if(cnt<=2)
				printf("yes\n");
			else printf("no\n");
		}
	}
}

 

 不会,可能和差分约束那一套有关吗??(乱说的

反正不会

暴扣50分

后话

出名单了,省四校二,膜拜cy大佬%%%

D题有不用莫队的nlogn解法

F题好像有bug,应该用dp来验证?

I题是把数分解为x^2*y^3然后枚举就可以了,当年powerful_number也是这么做的。

J题还没看。

反省一下,前面每道题的反应时间太慢了,不然可以有更多时间去肝最后两道大题

推E题公式的时候把循环中的i写成了n,调了半个小时

D题也没有很快地想到莫队

H题也许会被卡精度,应该用叉积来判断先后关系,总体来说还是有惊无险。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值