差点又爆零 :-(
prob1:书堆
好吧,没想到是栽在数学上
可以根据数学归纳法和物理中的杠杆原理得到\(Ans=\frac{m}{2}* \sum_{i=1}^n\frac{1}{i}\)
拓展:当\(n\)趋于极大值时,有调和级数公式\(\sum_{i=1}^n\frac{1}{i}=ln(n+1)+r\),其中\(r\)为欧拉常数,其近似值为\(0.5772156649\)
关于证明,还是看百科的吧……
于是题被秒了:
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const double eps=1e-9;
jinitaimei main()
{
int n=in,m=in;
double ans=0;
if(n>=1e7) ans=(log(n+1)+0.5772156649)/2;
else fur(i,1,n) ans+=1.0/(double)(i*2.0);
ans=ans*(double)m-eps;
cout<<(int)ans<<endl;
return 0;
}
prob2:最长距离
最短路锅了,T_T……
最短路跑点\((i,j)\)到点\((x,y)\)所需要联通的最短路(即最少需移走的障碍数目),对于满足距离小于\(T\)的进行距离取大即可。
考虑到\(T\)较小,可以记忆化深搜加剪枝,枚举每个点为起点即可。
最后一点:输出时再开方,防止掉精度:
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
#define db double
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=35;
int dis[xx][xx],mood[xx][xx],t,n,m;
db res=0;
inline void dfs(int x,int y,int sum)
{
if(sum>t) return;
if(sum>=dis[x][y]) return;
dis[x][y]=sum;
fur(i,-1,1) fur(j,-1,1) if(i!=j&&i!=-j)
{
int nx=x+i,ny=y+j;
if(nx>=1&&nx<=n&&ny>=1&&ny<=m) dfs(nx,ny,sum+mood[nx][ny]);
}
}
jinitaimei main()
{
n=in;m=in;t=in;
fur(i,1,n)
{
char op[35];
scanf("%s",op);
fur(j,0,m-1) mood[i][j+1]=op[j]-'0';
}
fur(i,1,n) fur(j,1,m)
{
fur(q,1,n) fur(p,1,m) dis[q][p]=1e5;
dfs(i,j,mood[i][j]);
fur(q,1,n) fur(p,1,m) if(dis[q][p]<=t) res=max(res,pow(abs(q-i),2)+pow(abs(p-j),2));
}
printf("%.6lf\n",sqrt(res));
return 0;
}
prob3:紧急集合/聚会
没想到错得跟\(zsb\)大佬开始错的一模一样
题解还是看他的吧,伤心欲绝
代码:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define jinitaimei signed
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=5e5+10,inf=0x7fffffff;
int top[xx],fa[xx],son[xx],dep[xx],sz[xx];
vector<int>e[xx];
inline void dfs1(int g)
{
sz[g]=1;
fur(i,0,(int)e[g].size()-1)
{
if(e[g][i]==fa[g]) continue;
fa[e[g][i]]=g;
dep[e[g][i]]=dep[g]+1;
dfs1(e[g][i]);
sz[g]+=sz[e[g][i]];
if(sz[e[g][i]]>sz[son[g]]) son[g]=e[g][i];
}
}
inline void dfs2(int g,int gg)
{
top[g]=gg;
if(son[g]) dfs2(son[g],gg);
fur(i,0,(int)e[g].size()-1) if(e[g][i]!=son[g]&&e[g][i]!=fa[g]) dfs2(e[g][i],e[g][i]);
}
inline int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
inline int dis(int u,int v,int all){return dep[u]+dep[v]-2*dep[all];}
jinitaimei main()
{
int n=in,m=in;
fur(i,1,n-1)
{
int x=in,y=in;
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(1);dfs2(1,1);
fur(i,1,m)
{
int x=in,y=in,z=in;
int t1=lca(y,z),t2=lca(x,z),t3=lca(x,y);
int s1=lca(x,t1),s2=lca(y,t2),s3=lca(z,t3);
int ans=inf,pos=0;
if(dis(y,z,t1)+dis(t1,x,s1)<ans) ans=dis(y,z,t1)+dis(t1,x,s1),pos=t1;
if(dis(x,z,t2)+dis(t2,y,s2)<ans) ans=dis(x,z,t2)+dis(t2,y,s2),pos=t2;
if(dis(x,y,t3)+dis(t3,z,s3)<ans) ans=dis(x,y,t3)+dis(t3,z,s3),pos=t3;
printf("%lld %lld\n",pos,ans);
}
return 0;
}
prob4:地精部落
一道\(DP\)大仙题
题解看这个,应该会说得比我清楚
代码:
#include<iostream>
#include<cstdio>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=4e3+210;
int dp[2][xx];
jinitaimei main()
{
int ans=0,n=in,p=in;
dp[0][2]=1;
fur(i,3,n) fur(j,2,i) dp[i&1][j]=(dp[i&1][j-1]+dp[(i-1)&1][i-j+1])%p;
fur(i,1,n) (ans+=dp[n&1][i])%=p;
printf("%lld\n",(ans<<1)%p);
return 0;
}
porb5:纪念品盒
可以证明,中间每\(k\)个人都全部取满,两边有余会是最优。
关于正确性\(yy\)一下就好了,中间的跑过去再回来肯定会远些,如果还不跑满那就很划不来了。
所以枚举开始余的大小就行了……
还算简单??
注意\(INF\)取大一点:
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define int long long
#define jinitaimei signed
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=1e7+10;
int dis[xx],diss[xx],disss[xx];
jinitaimei main()
{
int n=in,k=in,l=in;
fur(i,1,n)
{
disss[i]=in;
dis[i]=min(disss[i],l-disss[i]);
}
fur(i,1,n) diss[i]=dis[i]+dis[min(i+k-1,n)]+disss[min(i+k-1,n)]-disss[i];
int ans=1e18;
fur(i,1,k)
{
int tmp=dis[1]+dis[i]+disss[i]-disss[1],num=i+1;
while(num<=n)
{
tmp+=diss[num];
num+=k;
}
ans=min(ans,tmp);
}
printf("%lld\n",ans);
return 0;
}