20240405比赛总结
寄的很惨
T1 [JLOI2014] 聪明的燕姿
https://gxyzoj.com/d/hzoj/p/3672
敲个警钟,千万不要用一些奇怪的方法写自己会的题,不然大概率会一分不剩
由小学奥数知识,约数和的求法为
所以,可以先线性预处理出约数和,再直接统计,时间复杂度
考虑优化,显然,约数和也是一个乘积所以可以枚举其因子,注意,同一个p只可以使用一次
所以可以dfs,记录当前的答案和剩余的数,但是,2e9以内的质数不会少于5e7个,所以,还要优化
因为一个数n中不会出现两个超过
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=2e9;
int s,idx,ans,t[100005];
bool get_prime(int x)
{
if(x==1||x==0) return 0;
for(int i=2;i<=x/i;i++)
{
if(x%i==0) return 0;
}
return 1;
}
int cnt,p[50005];
bool vis[50005];
void dfs(int x,int num,int id)
{
//printf("%d %d %d\n",x,num,id);
if(x==1)
{
t[++ans]=num;
return;
}
for(int i=id;i<=cnt&&p[i]*p[i]<=x;i++)
{
ll tmp=1,sum=1;
for(int j=1;;j++)
{
tmp*=p[i];
sum+=tmp;
if(sum<=x)
{
if(x%sum==0)
{
dfs(x/sum,num*tmp,i+1);
}
}
else break;
}
}
if(get_prime(x-1)&&x-1&&x-1>=p[id]) t[++ans]=(x-1)*num;
}
int main()
{
for(int i=2;i<=50000;i++)
{
if(!vis[i]) p[++cnt]=i;
for(int j=1;i*p[j]<=50000;j++)
{
vis[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
while(cin>>s)
{
ans=0;
dfs(s,1,1);
sort(t+1,t+ans+1);
int tmp=ans;
for(int i=1;i<=ans;i++)
{
if(t[i]==t[i-1]) tmp--;
}
printf("%d\n",tmp);
for(int i=1;i<=ans;i++)
{
if(t[i]!=t[i-1]) printf("%d ",t[i]);
}
if(ans)
printf("\n");
}
return 0;
}
T2 luogu4550收集邮票
https://gxyzoj.com/d/hzoj/p/3671
设
很明显
先考虑
所以,得:
接着考虑g,有f的结论可以得到
为什么式子这样写?因为越往后每次的花费越大,所以后面在多取一次后都要加1,而本身这多取的一次也要加1,所以可得上述式子
化简得:
代码:
#include<cstdio>
using namespace std;
int n;
double f[10004],g[10004];
int main()
{
scanf("%d",&n);
for(int i=n-1;i>=0;i--)
{
f[i]=f[i+1]+1.0*n/(n-i);
g[i]=1.0*n/(n-i)+f[i]*i/(n-i)+f[i+1]+g[i+1];
}
printf("%.2lf",g[0]);
return 0;
}
T3 [HAOI2018] 苹果树
https://gxyzoj.com/d/hzoj/p/3665
最简单的想法,直接暴力枚举树的形态,再暴力计算两点之间的距离,时间复杂度
转换思路,可以从边考虑,设深度较大的一点是i,则i子树内一点到i子树外一点的路径必然经过该边,方案数:
因为总形态数为n!,所以只用考虑有多少种情况满足i的子树大小为
本题n的范围是2000,所以,时间复杂度为
考虑枚举节点i和其子树大小
分别考虑i的子树内与子树外的方案数
首先,因为i的子树内的节点编号必然大于i,树的形态为i!,所以子树内的方案数为
再考虑子树外,在放i之前,方案数为i!,放i之后,剩余的点就不能放在i的子树内了,所以方案数为:
所以子树外的总方案数为
相乘后就是答案
代码:
#include<cstdio>
#define ll long long
using namespace std;
int n,p;
ll fac[2005],C[2005][2005],ans;
int main()
{
scanf("%d%d",&n,&p);
fac[0]=1;
for(int i=1;i<=n;i++)
{
fac[i]=fac[i-1]*i%p;
}
C[0][0]=1;
for(int i=1;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
{
C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n-i+1;j++)
{
ans+=j*(n-j)%p*fac[j]%p*C[n-i][j-1]%p*i%p*(i-1)%p*fac[n-j-1]%p;
ans%=p;
}
}
printf("%d",ans);
return 0;
}
T4 [HAOI2012]高速公路
https://gxyzoj.com/d/hzoj/p/P691
考虑最朴素的式子
可以将边转化为点,则每个点的经过次数乘该点的权值就是答案,同时r也要-1,所以式子是:
时间复杂度
考虑优化:看到数据范围和区间修改,很明显是线段树
将第个式子拆开,得到:
记
在修改时,sum1可以直接进行更改,而sum2和sum3则需要记录两个值sum4和sum5
其中
这两个值可以在预处理时直接计算,所以,时间复杂度
记得开long long
代码:
#include<cstdio>
#include<iostream>
#define ll long long
#define lid id<<1
#define rid id<<1|1
using namespace std;
int n,m;
struct seg_tree{
int l,r;
ll sum[6],lazy;
}tr[800040];
void build(int id,int l,int r)
{
tr[id].l=l,tr[id].r=r;
if(l==r)
{
tr[id].sum[4]=l;
tr[id].sum[5]=1ll*l*l;
return;
}
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
tr[id].sum[4]=tr[lid].sum[4]+tr[rid].sum[4];
tr[id].sum[5]=tr[lid].sum[5]+tr[rid].sum[5];
}
void pushdown(int id)
{
if(tr[id].lazy)
{
tr[lid].lazy+=tr[id].lazy;
tr[rid].lazy+=tr[id].lazy;
tr[lid].sum[1]+=tr[id].lazy*(tr[lid].r-tr[lid].l+1);
tr[rid].sum[1]+=tr[id].lazy*(tr[rid].r-tr[rid].l+1);
tr[lid].sum[2]+=tr[id].lazy*tr[lid].sum[4];
tr[rid].sum[2]+=tr[id].lazy*tr[rid].sum[4];
tr[lid].sum[3]+=tr[id].lazy*tr[lid].sum[5];
tr[rid].sum[3]+=tr[id].lazy*tr[rid].sum[5];
tr[id].lazy=0;
}
}
void update(int id,int l,int r,ll c)
{
if(tr[id].l==l&&tr[id].r==r)
{
tr[id].sum[1]+=c*(r-l+1);
tr[id].lazy+=c;
tr[id].sum[2]+=c*tr[id].sum[4];
tr[id].sum[3]+=c*tr[id].sum[5];
return;
}
pushdown(id);
int mid=(tr[id].l+tr[id].r)>>1;
if(r<=mid) update(lid,l,r,c);
else if(l>mid) update(rid,l,r,c);
else update(lid,l,mid,c),update(rid,mid+1,r,c);
tr[id].sum[1]=tr[lid].sum[1]+tr[rid].sum[1];
tr[id].sum[2]=tr[lid].sum[2]+tr[rid].sum[2];
tr[id].sum[3]=tr[lid].sum[3]+tr[rid].sum[3];
}
ll sum1,sum2,sum3;
void query(int id,int l,int r)
{
if(l==tr[id].l&&tr[id].r==r)
{
sum1+=tr[id].sum[1];
sum2+=tr[id].sum[2];
sum3+=tr[id].sum[3];
return;
}
pushdown(id);
int mid=(tr[id].l+tr[id].r)>>1;
if(r<=mid) query(lid,l,r);
else if(l>mid) query(rid,l,r);
else query(lid,l,mid),query(rid,mid+1,r);
}
ll gcd(ll a,ll b)
{
if(b==0) return a;
return gcd(b,a%b);
}
int main()
{
scanf("%d%d",&n,&m);
build(1,1,n-1);
while(m--)
{
char opt;
cin>>opt;
if(opt=='C')
{
int l,r;
ll v;
scanf("%d%d%lld",&l,&r,&v);
update(1,l,r-1,v);
}
else
{
sum1=sum2=sum3=0;
int l,r;
scanf("%d%d",&l,&r);
r--;
query(1,l,r);
ll a=sum1*(r-l+1-1ll*r*l)+(l+r)*sum2-sum3;
ll b=1ll*(r+1-l)*(r-l+2)/2;
ll d=gcd(a,b);
printf("%lld/%lld\n",a/d,b/d);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律