「JXOI2018」游戏
显然只要检查完所有除自己外没有范围 [ l , r ] [l,r] [l,r]的因数的数就可以使所有办公室开始认真工作,那么只需要求出这种数有多少,后面就随便算了。那么只需要知道最大因数是否在 [ l , r ] [l,r] [l,r]内,线性筛出每个数的最小质因数就可以知道最大因数了。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int inf=2147483647;
const int mod=1000000007;
const int Maxn=10000010;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
void upd(int&x,int y){x+=y;if(x>=mod)x-=mod;}
int Pow(int x,int y)
{
if(!y)return 1;
int t=Pow(x,y>>1),re=(LL)t*t%mod;
if(y&1)re=(LL)re*x%mod;
return re;
}
int n,m=0,l,r,f[Maxn],prime[1000000],tot=0,inv[Maxn];
bool mark[Maxn];
void pre()
{
inv[0]=inv[1]=1;for(int i=2;i<=r;i++)inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
f[1]=2;
for(int i=2;i<=r;i++)
{
if(!mark[i])f[i]=i,prime[++tot]=i;
for(int j=1;j<=tot&&prime[j]*i<=r;j++)
{
mark[prime[j]*i]=true;
f[prime[j]*i]=prime[j];
if(i%prime[j]==0)break;
}
}
}
int main()
{
l=read(),r=read();n=r-l+1;pre();
for(int i=l;i<=r;i++)if(i/f[i]<l)m++;
int ans=0,t=1,C=1;
for(int i=2;i<=n-m;i++)t=(LL)t*i%mod;
for(int i=2;i<=m;i++)t=(LL)t*i%mod;
for(int p=m;p<=n;p++)
{
upd(ans,(LL)C*t%mod*p%mod);
C=(LL)C*p%mod*inv[p-m+1]%mod;
}
printf("%d",ans);
}
「JXOI2018」排序问题
稍微推一下式子就发现每次加入的数就是当前最少的那个,然后模拟这个过程就可以了。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=200010;
const int Maxm=10000010;
const int inf=2147483647;
const int mod=998244353;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,l,r,a[Maxn],b[Maxn],ans,inv[Maxm],fin[Maxm],cnt[Maxn],fac[Maxm];
unordered_map<int,int>c;
int Pow(int x,int y)
{
if(!y)return 1;
int t=Pow(x,y>>1),re=(LL)t*t%mod;
if(y&1)re=(LL)re*x%mod;
return re;
}
int main()
{
fac[0]=1;for(int i=1;i<=10000000;i++)fac[i]=(LL)fac[i-1]*i%mod;
inv[0]=inv[1]=1;for(int i=2;i<=10000000;i++)inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
fin[0]=1;for(int i=1;i<=10000000;i++)fin[i]=(LL)fin[i-1]*inv[i]%mod;
int T=read();
while(T--)
{
int N;
n=read(),m=read(),l=read(),r=read();N=n;
ans=fac[m];
for(int i=1;i<=n;i++)a[i]=b[i]=read(),c[a[i]]++,ans=(LL)ans*(i+m)%mod;
sort(a+1,a+1+n);n=unique(a+1,a+1+n)-(a+1);
int L=n+1,R=0;
for(int i=1;i<=n;i++)
if(a[i]<l)ans=(LL)ans*fin[c[a[i]]]%mod;
else{L=i;break;}
for(int i=n;i;i--)
if(a[i]>r)ans=(LL)ans*fin[c[a[i]]]%mod;
else{R=i;break;}
for(int i=0;i<=N;i++)cnt[i]=0;
cnt[0]=r-l+1-(R-L+1);
for(int i=L;i<=R;i++)cnt[c[a[i]]]++;
for(int i=0;i<N;i++)
{
if(cnt[i]<=m)
{
cnt[i+1]+=cnt[i];
m-=cnt[i];cnt[i]=0;
}
else
{
cnt[i+1]+=m;
cnt[i]-=m;m=0;break;
}
}
if(!m)
{
for(int i=2;i<=N;i++)ans=(LL)ans*Pow(fin[i],cnt[i])%mod;
}
else
{
int p=N+m/cnt[N],v2=m%cnt[N],v1=cnt[N]-v2;
ans=(LL)ans*Pow(fin[p],v1)%mod;
ans=(LL)ans*Pow(fin[p+1],v2)%mod;
}
printf("%d\n",ans);
for(int i=1;i<=N;i++)c[b[i]]--;
}
}
「JXOI2018」守卫
枚举右端点 r r r,显然 r r r必须要放,那么 r r r看不到的一定是若干个区间,设他们为 [ l i , r i ] [l_i,r_i] [li,ri],那么若要覆盖这些,最后一个要么放在 r i r_i ri,要么放在 r i + 1 r_i+1 ri+1,因为 r i + 2 r_i+2 ri+2以及之后是看不到 r i r_i ri的。那么就好办了,直接 f l , r f_{l,r} fl,r表示这段最少放多少就可以了。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=5010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,f[Maxn][Maxn],tmp[Maxn],lt;LL h[Maxn];
int main()
{
n=read();
for(int i=1;i<=n;i++)h[i]=read();
int ans=0;
for(int i=1;i<=n;i++)
{
f[i][i]=f[i-1][i]=1;
LL y=h[i]-h[i-1],x=1;
bool fir=true;int r;
for(int j=i-2;j>0;j--)
{
LL Y=h[i]-h[j],X=i-j;
if(Y*x<X*y)f[j][i]=f[j+1][i],fir=true,x=X,y=Y;
else
{
if(fir)f[j][i]=f[j+1][i]+1,fir=false,r=j;
else f[j][i]=min(f[j][r]+f[r+1][i],f[j][r+1]+f[r+2][i]);
}
}
}
for(int l=1;l<=n;l++)
for(int r=l;r<=n;r++)
ans^=f[l][r];
printf("%d",ans);
}