8.19NOIP Day5模拟赛
T1
观察到连边构成了一大堆互不相同的链,考虑算出每一种长度链的数量
\(a=1\) 时单独讨论,其他情况链长都不会超过 \(log\) 级
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
int n,a,b;
scanf("%lld%lld%lld",&n,&a,&b);
if(a==1&&b<=sqrt(n)){
int ans=0;
for(int i=1;i<=b;i++)ans+=(n-i)/b/2+1;
printf("%lld\n",ans);
return 0;
}
int flag=0,summ=0,p=1,now=0,ans=0,add=0;
while(summ+p<=n){
p=p*a;
summ*=a;
summ+=b;
now++;
}
for(int i=now;i;i--){
p/=a;
summ-=b;
summ/=a;
int to=(n-summ)/p;
ans+=(to-flag-add)*((i+1)/2);
add+=to-flag-add;
flag=to;
}
printf("%lld\n",ans);
return 0;
}
T2
朴素的DP就是记录下最后三位的大小,但是我们可以把它优化成后缀gcd,这样的话每一个后缀gcd都是前一个的倍数,状态大量减少,然后使用滚动数组优化空间
#include<bits/stdc++.h>
#define int long long
#define N 205
#define mod 1000000007
#define M 105
using namespace std;
int L[N],R[N],f[N][N],dp[2][M][M][M];
signed main(){
int n,m=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld%lld",&L[i],&R[i]);
for(int i=1;i<=n;i++)m=max(m,R[i]);
for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)f[i][j]=__gcd(i,j);
for(int i=L[1];i<=R[1];i++)for(int j=L[2];j<=R[2];j++)for(int k=L[3];k<=R[3];k++)dp[1][f[i][f[j][k]]][f[j][k]][k]++;
for(int i=4;i<=n;i++){
int u=(i&1),v=(u^1);
memset(dp[u],0,sizeof(dp[u]));
for(int j=L[i];j<=R[i];j++)for(int k=1;k<=m;k++)for(int l=k;l<=m;l+=k)for(int h=l;h<=m;h+=l)dp[u][f[l][j]][f[h][j]][j]=(dp[u][f[l][j]][f[h][j]][j]+dp[v][k][l][h]*(f[j][k]+1)%mod)%mod;
}
int ans=0;
for(int i=1;i<=m;i++)for(int j=i;j<=m;j+=i)for(int k=j;k<=m;k+=j)ans=(ans+dp[n&1][i][j][k])%mod;
printf("%lld\n",ans);
return 0;
}
T3
我们对于每一个点 \(i\) 暴力维护从它出发,终点 \(\le j\) 的数量,然后进行无限分讨。
#include<bits/stdc++.h>
#define N 505
using namespace std;
int s[N][N],y[N][N],n,q;
signed main(){
int op,u,v,summ=0,a,b;
scanf("%d%d",&n,&q);
while(q--){
scanf("%d%d%d",&op,&u,&v);
if(u>v)swap(u,v);
if(op==1){
for(int i=v;i<=n;i++){
y[u][i]++;
s[u][i]+=v-u;
}
summ+=v-u;
}
else{
int now=0,mid=u+(v-u+1)/2;
for(int i=1;i<=u;i++){
now+=(y[i][n]-y[i][v])*(v-u);
a=y[i][v]-y[i][mid-1];
b=s[i][v]-s[i][mid-1];
now+=b-(a*(v-i)-b+a*(u-i));
}
for(int i=u+1;i<mid;i++){
now+=(y[i][n]-y[i][v])*((v-i)-(i-u));
int to=i+i-u+(v-(i+i-u)+1)/2;
a=y[i][v]-y[i][to-1];
b=s[i][v]-s[i][to-1];
now+=b-(a*(v-u)-b);
}
printf("%d\n",summ-now);
}
}
return 0;
}

浙公网安备 33010602011771号