LGR-072 div2 小结

T1

签到题,但是注意读入要用 long long 而不是 unsigned long long,以及负数的答案为 0 0 0

代码(略去了原代码中多余的东西):

ll n;

void main()
{
	scanf("%lld",&n);
	if(n<=0)printf("0");
	else printf("%llu",((ull)n-1llu)*2llu+1llu);
}

T2

这题爆搜出每一段座位,然后每一段座位中,第一个座位有 k k k 个学校可选,后面的座位由于不能和上一个座位学校相同,所以只有 k − 1 k-1 k1 种颜色选,每段座位的答案乘起来就是最终答案了。

代码:

int n,m,k,one,two,oth;
char s[maxn][maxn];
bool v[maxn][maxn];
int fx[4]={0,1,0,-1},fy[4]={1,0,-1,0};
void go(int x,int y)
{
	v[x][y]=true;int tot=0;
	for(int i=0;i<4;i++)
	{
		int xx=x+fx[i],yy=y+fy[i];
		if(xx<1||xx>n||yy<1||yy>m)continue;
		if(s[xx][yy]=='O')
		{
			tot++;
			if(!v[xx][yy])go(xx,yy);
		}
	}
	if(tot==1)one++;
	if(tot==2)two++;
	if(tot>2)oth++;
}
ll ans=1;

void main()
{
	scanf("%d %d %d",&n,&m,&k);k%=mod;
	for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	if(s[i][j]=='O'&&!v[i][j])
	{
		one=two=oth=0,go(i,j);
		if(!oth)
		{
			if(one==2)ans=ans*k%mod*ksm(k-1,two+one-1)%mod;
			else if(!one&&!two)ans=ans*k%mod;
			else {printf("0");return;}
		}
		else {printf("0");return;}
	}
	printf("%lld",ans);
}

T3

本人数学太菜,所以当时只能码了个 80 80 80 分的暴力。

考虑每一个能化成有限小数的分数,约了分之后分母肯定只有 2 , 5 2,5 2,5 两个质因数,所以一定能表示成 d x 2 a 5 b d \dfrac {dx} {2^a5^bd} 2a5bddx,其中 d d d 是分子分母的 gcd ⁡ \gcd gcd

由于分子满足 d x ≤ n dx\leq n dxn,即 x ≤ ⌊ n d ⌋ x\leq \lfloor \dfrac n d \rfloor xdn,所以每个 d d d 能贡献出 ⌊ n d ⌋ \lfloor \dfrac n d \rfloor dn 个满足要求的分数,可以发现 d d d 可以用整除分块来枚举。

然后 a , b a,b a,b 暴力枚举即可,然后注意枚举 d d d 的时候 2 a 5 b d 2^a5^bd 2a5bd 也要小于 n n n

代码:

#define ll long long
ll n,ans=0,two[50],five[50];
inline ll get(ll l,ll r){return r-l+1-(r/2-(l-1)/2)-(r/5-(l-1)/5)+(r/10-(l-1)/10);}
struct par{ll r,sum;}s[10000010];int t=0;

void main()
{
	scanf("%lld",&n);
	two[0]=1;for(int i=1;i<=40;i++)two[i]=two[i-1]*2;
	five[0]=1;for(int i=1;i<=20;i++)five[i]=five[i-1]*5;
	for(ll l=1,r;l<=n;l=r+1)
	{
		s[++t].r=r=n/(n/l);
		s[t].sum=s[t-1].sum+get(l,r)*(n/l);
	}
	for(int i=0;two[i]<=n;i++)
	for(int j=0;two[i]*five[j]<=n;j++)
	{
		ll lim=n/(two[i]*five[j]);
		#define mid (l+r>>1)
		int l=1,r=t,p;while(l<=r)if(s[mid].r<=lim)p=mid,l=mid+1;else r=mid-1;
		ans+=s[p].sum+(lim-s[p].r)*(n/(s[p].r+1));
	}
	printf("%lld\n",ans);
}

T4

T3没做出来的我居然会T4啊……

这题是个简单的贪心,显然每次只考虑往最远的 y o u y o u youyou youyou 走,而每次走一步,走到的那个子树内的 y o u y o u youyou youyou 离小 Z Z Z 的距离就 − 2 -2 2,而其他的 y o u y o u youyou youyou 离小 Z Z Z 的距离不变。

a = a= a= 离次远 y o u y o u youyou youyou 的距离, b = b= b= 离最远 y o u y o u youyou youyou 的距离,假如 ∣ a − b ∣ ≤ 1 |a-b|\leq 1 ab1,那么就没必要走了。

于是过程中动态维护一下 a a a 即可,细节有一点多,具体看代码:

//由于是比赛代码,有什么多余的东西也见怪不怪了qwq
int n,m,S,k;
struct edge{int y,next;}e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
bool v[maxn];//记录每个点是否有youyou
int far[maxn],dir[maxn];//far[x]记录以S为根,x的子树内深度最大的点离x的距离
//dir[x]表示深度最大点在x的哪个儿子的子树内
void dfs(int x,int fa)
{
	for(int i=first[x];i;i=e[i].next)
	{
		int y=e[i].y;if(y==fa)continue;
		dfs(y,x);if(v[y]&&far[x]<1)far[x]=1,dir[x]=y;
		if(far[y]&&far[y]+1>far[x])far[x]=far[y]+1,dir[x]=y;
	}
}
int r=0,sec=0;//r表示经过了多少轮,sec记录次远点
int step(int x,int fa)
{
	if(far[x]-r-k<=0)return 0;//能干掉最远点
	for(int i=first[x];i;i=e[i].next)
	if(e[i].y!=fa&&e[i].y!=dir[x])sec=max(sec,far[e[i].y]+1-r);
	if(sec<=k)sec=0;//要注意次远点能被干掉的情况
	if((far[x]-r-sec)/2)return r++,step(dir[x],x)+1;
	else return far[x]-r-k;
}

void main()
{
	read(n);
	for(int i=1,x,y;i<n;i++)read(x),read(y),
	buildroad(x,y),buildroad(y,x);
	scanf("%d",&m);
	for(int i=1,x;i<=m;i++)scanf("%d",&x),v[x]=true;
	scanf("%d %d",&k,&S);
	dfs(S,0);
	if(far[S]<=k){printf("1\n");return;}
	printf("%d",step(S,0)+1);//+1是算上最后干掉最远点的那一轮
	fcheck(1);return;//这个fcheck是和输出有关的,和此题无关
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值