复健练习(2019年8月26日)

差点又爆零 :-(

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;
}

猜你喜欢

转载自www.cnblogs.com/ALANALLEN21LOVE28/p/11413809.html