CF935 Codeforces Round 465 (Div. 2)

CF935A Fafa and his Company

大概是 \(n\) 的因数个数减一?


#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n;
int main()
{
	scanf("%d",&n);
	int ans=1;
	for(int i=2;i<=sqrt(n);i++)
		if(n%i==0)
		{
			int cnt=0;
			while(n%i==0) n/=i,cnt++;
			ans*=(cnt+1);
		}
	if(n!=1) ans*=2;
	printf("%d",ans-1);
	return 0;
}

CF935B Fafa and the Gates

直接模拟?


#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005;
int n;
char s[N];
int main()
{
	scanf("%d",&n);
	scanf("%s",s+1);
	int x=0,y=0;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='R') x++;
		else if(s[i]=='U') y++;
		if(x==y)
		{
			if(s[i]==s[i+1]) ans++;
		}
	}
	printf("%d",ans);
	return 0;
}

CF935C Fifa and Fafa

计算出直线 \((x_1,y_1),(x_2,y_2)\) 与圆的交点,圆心在距离 \((x_1,y_1)\) 较远的点和 \((x_1,y_1)\) 的中点上,特判 \((x_1,y_1)\) 不在圆中和 \((x_1,y_1),(x_2,y_2)\) 重合的情况。


#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
double dis(double x1,double y1,double x2,double y2)
{
	return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
int main()
{
	double R,x1,y1,x2,y2;
	scanf("%lf%lf%lf%lf%lf",&R,&x1,&y1,&x2,&y2);
	if(dis(x1,y1,x2,y2)>R)
	{
		printf("%.7lf %.7lf %.7lf",x1,y1,R);
		return 0;
	}
	if(x1==x2&&y1==y2)
	{
		printf("%.7lf %.7lf %.7lf",x1-R/2.0,y1,R/2.0);
		return 0;
	}
	double kx=(x1-x2)/dis(x1,y1,x2,y2),ky=(y1-y2)/dis(x1,y1,x2,y2);
	double dx=x1+R*kx,dy=y1+R*ky;
	double xap=(dx+x2)/2,yap=(dy+y2)/2,d=dis(xap,yap,x2,y2);
	printf("%.7lf %.7lf %.7lf",xap,yap,d);
	return 0;
}

CF935D Fafa and Ancient Alphabet

\(f_i\) 表示从后往前到第 \(i\) 个字符,\(S_1> S_2\) 的概率。直接转移。


#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005;
const int MOD=1000000007;
int n,m;
int a[N],b[N];
long long ksm(long long a,long long b)
{
	long long res=1;
	while(b)
	{
		if(b&1) res=res*a%MOD;
		a=a*a%MOD,b>>=1;
	}
	return res;
}
long long f[N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
		scanf("%d",&b[i]);
	long long inv=ksm(m,MOD-2);
	for(int i=n;i>=1;i--)
	{
		if(a[i]&&b[i]) f[i]=a[i]==b[i]?f[i+1]:a[i]>b[i];
		else if(a[i]) f[i]=(a[i]-1+f[i+1])*inv%MOD;
		else if(b[i]) f[i]=(m-b[i]+f[i+1])*inv%MOD;
		else f[i]=(1LL*m*(m-1)/2%MOD+f[i+1]*m%MOD)*inv%MOD*inv%MOD;
	}
	printf("%lld",f[1]);
	return 0;
}

CF935E Fafa and Ancient Mathematics

不妨令 \(P\le M\)\(P> M\) 时同理。

先建出表达式树,那么就有一个 DP:令 \(f_{u,i}\) 表示以 \(u\) 为根,选了 \(i\) 个加号的最大值;令 \(g_{u,i}\) 表示以 \(u\) 为根,选了 \(i\) 个加号的最小值。转移类似树形背包。


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=10005,M=105;
int n;
char s[N];
int p,m;
int lim;
int dp[2][N][M];
int ch[N][2],tot=1;
int fa[N];
void dfs(int u)
{
	if(!ch[u][0]) return;
	dfs(ch[u][0]);
	dfs(ch[u][1]);
	for(int i=0;i<=lim;i++)
		for(int j=0;i+j<=lim;j++)
		{
			dp[0][u][i+j+(p<m)]=max(dp[0][u][i+j+(p<m)],dp[0][ch[u][0]][i]+dp[0][ch[u][1]][j]);
			dp[0][u][i+j+(p>=m)]=max(dp[0][u][i+j+(p>=m)],dp[0][ch[u][0]][i]-dp[1][ch[u][1]][j]);
			dp[1][u][i+j+(p<m)]=min(dp[1][u][i+j+(p<m)],dp[1][ch[u][0]][i]+dp[1][ch[u][1]][j]);
			dp[1][u][i+j+(p>=m)]=min(dp[1][u][i+j+(p>=m)],dp[1][ch[u][0]][i]-dp[0][ch[u][1]][j]);
		}
	return;
}
int main()
{
	scanf("%s",s+1);
	scanf("%d%d",&p,&m);
	n=strlen(s+1);
	lim=min(p,m);
	memset(dp[0],-63,sizeof(dp[0]));
	memset(dp[1],63,sizeof(dp[1]));
	tot=1;
	int pre=tot;
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='('||s[i]=='?')
		{
			ch[pre][ch[pre][0]?1:0]=++tot;
			fa[tot]=pre;
			pre=tot;
		}
		else if(s[i]==')') pre=fa[pre];
		else dp[0][tot][0]=dp[1][tot][0]=s[i]-'0',pre=fa[pre];
	}
	dfs(1);
	printf("%d",dp[0][1][lim]);
	return 0;
}

CF935F Fafa and Array

考虑 \(a_i\) 加上 \(x\)\(f(A)\) 的变化量 \(\delta\)

  • 对于 \(i=1\)\(\delta = |a_1+x-a_2|-|a_1-a_2|\)
  • 对于 \(i=n\)\(\delta = |a_n-a_{n-1}+x|-|a_n-a_{n-1}|\)
  • 对于 \(2\leq i\leq n-1\)\(\delta = |a_i-a_{i-1}+x|+|a_{i+1}-a_i-x|-|a_i-a_{i-1}|-|a_{i+1}-a_i|\)

下文中只讨论 \(2\leq i\leq n-1\) 的情况,\(i=1,n\) 的情况特判即可。

我们可以分成几种情况分别讨论:

\(a_i+x\lt a_{i-1},a_i+x\lt a_{i+1}\)

\[\begin{aligned}\delta &=|a_i-a_{i-1}+x|+|a_{i+1}-a_i-x|-|a_i-a_{i-1}|-|a_{i+1}-a_i| \\ &=a_{i-1}-(a_i+x)+a_{i+1}-(a_i+x)-(a_{i-1}-a_i)-(a_{i+1}-a_i) \\ &=-2x\end{aligned} \]

\(a_{i-1}\lt a_i+x\lt a_{i+1}\)

\[\begin{aligned}\delta &=|a_i-a_{i-1}+x|+|a_{i+1}-a_i-x|-|a_i-a_{i-1}|-|a_{i+1}-a_i| \\ &=(a_i+x)-a_{i-1}+a_{i+1}-(a_i+x)-|a_i-a_{i-1}|-(a_{i+1}-a_i) \\ &=a_i-a_{i-1}-|a_i-a_{i-1}|< 0\end{aligned} \]

\(a_i+x\ge a_{i-1},a_i+x\ge a_{i+1}\)

\[\begin{aligned}\delta &=|a_i-a_{i-1}+x|+|a_{i+1}-a_i-x|-|a_i-a_{i-1}|-|a_{i+1}-a_i| \\ &=(a_i+x)-a_{i-1}+(a_i+x)-a_{i+1}-|a_i-a_{i-1}|-|a_i-a_{i+1}| \end{aligned} \]

继续分成三种情况:

  • 对于 \(a_i\ge a_{i-1},a_i\ge a_{i+1}\)\(\delta = 2x\)
  • 对于 \(a_{i-1}\le a_i\lt a_{i+1}\)\(\delta = 2(x-(a_{i+1}-a_i))\)
  • 对于 \(a_i\lt a_{i-1},a_i\lt a_{i+1}\)\(\delta = 2(x-((a_{i-1}-a_i)+(a_{i+1}-a_i)))\)

我们可以用线段树维护一下 \(\min\{\max(0,a_{i-1}-a_i)+\max(0,a_{i+1}-a_i)\}\)

\(c_i=a_i-a_{i+1}\),则我们需要维护 \(\min\{\max(0,c_{i-1})+\max(0,-c_i)\}\),第二个操作变成了单点加。

注意 \(l=r\) 时要特判。


#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=100005;
int n,Q;
int a[N];
long long c[N];
struct Node
{
	int l,r;
	long long Min;
}tree[N<<2];
void push_up(int i)
{
	tree[i].Min=min(tree[i*2].Min,tree[i*2+1].Min);
	return;
}
void build(int i,int l,int r)
{
	tree[i].l=l,tree[i].r=r;
	if(l==r)
	{
		tree[i].Min=max(0LL,c[l-1])+max(0LL,-c[l]);
		return;
	}
	int mid=(l+r)/2;
	build(i*2,l,mid);
	build(i*2+1,mid+1,r);
	push_up(i);
	return;
}
long long ans;
void modify(int i,int u,int v)
{
	if(tree[i].l==tree[i].r)
	{
		ans+=-abs(c[u])+abs(c[u]+v);
		c[u]+=v;
		tree[i].Min=max(0LL,c[u-1])+max(0LL,-c[u]);
		if(v&&u+1<=n-1) modify(1,u+1,0);
		return;
	}
	if(u<=tree[i*2].r) modify(i*2,u,v);
	else modify(i*2+1,u,v);
	push_up(i);
	return;
}
long long query(int i,int l,int r)
{
	if(l<=tree[i].l&&tree[i].r<=r) return tree[i].Min;
	if(r<=tree[i*2].r) return query(i*2,l,r);
	else if(l>=tree[i*2+1].l) return query(i*2+1,l,r);
	else return min(query(i*2,l,r),query(i*2+1,l,r));
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
		c[i]=a[i]-a[i+1];
	for(int i=1;i<=n-1;i++)
		ans+=abs(c[i]);
	build(1,2,n-1);
	scanf("%d",&Q);
	while(Q--)
	{
		int t,l,r,x;
		scanf("%d%d%d%d",&t,&l,&r,&x);
		if(t==1)
		{
			if(l==r)
			{
				if(l==1) printf("%lld\n",ans-abs(c[l])+abs(c[l]+x));
				else if(l==n) printf("%lld\n",ans-abs(c[l-1])+abs(c[l-1]-x));
				else printf("%lld\n",ans-abs(c[l-1])-abs(c[l])+abs(c[l-1]-x)+abs(c[l]+x));
			}
			else
			{
				long long del=2*(x-query(1,max(l,2),min(r,n-1)));
				if(l==1) del=max(del,(long long)-abs(c[l])+abs(c[l]+x));
				if(r==n) del=max(del,(long long)-abs(c[r-1])+abs(c[r-1]-x));
				printf("%lld\n",ans+max(0LL,del));
			}
		}
		else if(t==2)
		{
			if(r==n) ans+=-abs(c[n-1])+abs(c[n-1]-x),c[n-1]-=x,modify(1,n-1,0);
			else modify(1,r,x);
			if(l==1) continue;
			else if(l==2) ans+=-abs(c[1])+abs(c[1]-x),c[1]-=x,modify(1,2,0);
			else modify(1,l-1,-x);
		}
	}
	return 0;
}
posted @ 2023-09-27 22:12  Zhou_JK  阅读(28)  评论(0)    收藏  举报