(2021.1.25)训练题解(()王识尧())
(1.CodeForcesspace space CF935D)题解
题解
这道题一看就可以知道是概率(dp)。
(emm......),其实严格来讲没有太(dp),我们来考虑下怎么通过一步步递推得到答案。
首先,我们设题目中给你的两个数列是(S_1)和(S_2),两个数列的前缀分别为(Suff_1),(Suff_2)。
这样一来,我们射(S_1)在字典序意义下大于(S_2)的概率是数组(p),那么(p_i)就由当前位决定。
具体的:
(p_i=egin{cases} 0,space ifspace i==n\1,space ifspace S_{1_i}>S_{2_i} \ 0,space ifspace S_{1_i}<S_{2_i}\ p_{i+1},space ifspace S_{1_i}=S_{2_i} end{cases})
类似的,我们可以推出当有空缺时的答案,具体详见代码。
另外,因为题目要求逆元,我们还需要先求出一个逆元,之后每次直接乘即可。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
const int MOD=1e9+7;
int n,m;
int a[N],b[N];
int p[N],inv;
int Fpow(int x,int a)
{
int res=1,mul=x;
while (a)
{
if(a&1) res=(res*mul)%MOD;
mul=(mul*mul)%MOD;
a>>=1;
}
return res;
}
int INV(int x)
{
return Fpow(x,MOD-2);
}
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while (c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
signed main()
{
n=read(),m=read();
inv=INV(m);
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) b[i]=read();
for(int i=n;i>=1;i--)
{
if(a[i]!=0 && b[i]!=0)
{
if(a[i]>b[i]) p[i]=1;
if(a[i]==b[i]) p[i]=p[i+1];
if(a[i]<b[i]) p[i]=0;
}
else if(a[i]==0 && b[i]!=0) p[i]=((p[i+1]+(m-b[i]))%MOD*inv)%MOD;
else if(a[i]!=0 && b[i]==0) p[i]=((p[i+1]+(a[i]-1))%MOD*inv)%MOD;
else p[i]=(((p[i+1]*m%MOD+(m*(m-1)/2)%MOD)%MOD*inv)%MOD)*inv%MOD;
}
printf("%lld
",p[1]);
return 0;
}
(2.CodeForcesspace space CF930C)题解
题解
这道题需要我们换个角度考虑问题。
我们发现,如果存在一个“谷底”,即(x_1<x_2<x_3)且(cnt_{x_1}>cnt_{x_2},cnt_{x_2}<cnt_{x_3}),这样的情况下(cnt_{x_2})就一定没有被某些线段覆盖到,因为必定有线段在(x_1)或(x_3)那里停下了。
有了上述推论,我们来处理这道题。
我们将每个点的(cnt)值作为这个点参与运算时的值,在这种情况下找到两个峰值就可以判断这两个峰值之间的部分不满足条件。题目既然不让我们确定,那我们就找出不能确定(2)个峰值的最大集合大小,也就是最长单峰序列长度,为了求这个我们需要正反跑两遍最长上升子序列。
注意(cnt)值可以用差分来求。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,m,a[N],Forward[N],Backward[N],ans;
vector<int> numbers;
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while (c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
signed main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
int l=read(),r=read();
a[l]++,a[r+1]--;
}
for(int i=1;i<=m;i++) a[i]+=a[i-1];
numbers.clear();
numbers.push_back(a[1]);
Forward[1]=1;
for(int i=2;i<=m;i++)
{
if(a[i]>=numbers.back())
{
numbers.push_back(a[i]);
Forward[i]=numbers.size();
}
else
{
int pos=upper_bound(numbers.begin(),numbers.end(),a[i])-numbers.begin();
numbers[pos]=a[i];
Forward[i]=pos+1;
}
}
numbers.clear();
numbers.push_back(a[m]);
Backward[m]=1;
for(int i=m-1;i>=1;i--)
{
if(a[i]>=numbers.back())
{
numbers.push_back(a[i]);
Backward[i]=numbers.size();
}
else
{
int pos=upper_bound(numbers.begin(),numbers.end(),a[i])-numbers.begin();
numbers[pos]=a[i];
Backward[i]=pos+1;
}
}
for(int i=1;i<=m;i++) ans=max(ans,Forward[i]+Backward[i]-1);
printf("%lld
",ans);
return 0;
}
(3.CodeForcesspace space CF914D)题解
题解
这道题其实非常的简单。
他不是让我们至多修改一个数嘛?那我们就看看区间之内有多少个数非常不配合,不能被(x)整除。
如果这个答案他大于(1),直接结束,因为最多修改一个。
上述操作可以用区间查询来实现。
回答一个(lht)的问题,他硕你不能保证你当前序列中(x)时最大公因数,这个很好办,如果情况允许,你把任意一个改成(x)不就好了.................
代码
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
int tree[N<<2];
int n,m,a[N],cnt;
int read()
{
int x=0,f=1;
char c=getchar();
while (c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while (c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
int gcd(int x,int y)
{
if(!y) return x;
return gcd(y,x%y);
}
void push_up(int x)
{
tree[x]=gcd(tree[x<<1],tree[x<<1|1]);
}
void BuildTree(int p,int l,int r)
{
if(l==r)
{
tree[p]=a[l];
return ;
}
int mid=(l+r)>>1;
BuildTree(p<<1,l,mid);
BuildTree(p<<1|1,mid+1,r);
push_up(p);
}
void Query(int p,int l,int r,int L,int R,int d)
{
if(cnt>1 || tree[p]%d==0) return ;
if(l==r)
{
cnt++;
return ;
}
int mid=(l+r)>>1;
if(L<=mid) Query(p<<1,l,mid,L,R,d);
if(mid<R) Query(p<<1|1,mid+1,r,L,R,d);
}
void Modify(int p,int l,int r,int pos,int d)
{
if(l==r)
{
tree[p]=d;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) Modify(p<<1,l,mid,pos,d);
else Modify(p<<1|1,mid+1,r,pos,d);
push_up(p);
}
int main()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read();
m=read();
BuildTree(1,1,n);
while (m--)
{
int op=read();
if(op==1)
{
cnt=0;
int L=read(),R=read(),x=read();
Query(1,1,n,L,R,x);
if(cnt<=1) puts("YES");
else puts("NO");
}
else
{
int x=read(),y=read();
Modify(1,1,n,x,y);
}
}
return 0;
}