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;
}