51nod做题记录

1 篇文章 0 订阅

1024 数字0-9的数量

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1042

Hint(方法1):solve(r)-solve(l-1)、分成首位,中间位,末位瞎搞就好

Hint(方法2):数位dp

/*
2019/11/4
方法1
(懒得再开一个数组
直接在solve函数里求完了ans[r]-ans[l-1]
导致了代码非常冗长2333 
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

ll le,ri;
ll dp[15];

ll solve()
{
    ll rt=0,lt=0,sr=1,sl=1;
    bool f1=true,f2=true;
    while(ri)
    {
        if(ri<10)
        {
            for(int i=1;i<ri;i++)
            {
                dp[i]+=sr;
            }
            dp[ri]+=rt+1;
            break;
        }//首位

        int a=ri%10;
        ri/=10;
        if(f1)
        {
            for(int i=1;i<=a;i++)
                dp[i]++;
            for(int i=0;i<=9;i++)
                dp[i]+=ri;
        }//末位
        else
        {
            if(a!=0)
                dp[0]+=ri*sr;

            for(int i=1;i<a;i++)
                dp[i]+=(ri+1)*sr;

            if(a!=0)
                dp[a]+=ri*sr+rt+1;
            else
            {
                dp[a]+=(ri-1)*sr+rt+1;
            }

            for(int i=a+1;i<=9;i++)
                dp[i]+=ri*sr;

        }//中间位

        rt+=sr*a;sr*=10;
        f1=false;


    }
    while(le)
    {
        if(le<10)
        {
            for(int i=1;i<le;i++)
            {
                dp[i]-=sl;
            }
            dp[le]-=(lt+1);
            break;
        }//首位

        int a=le%10;
        le/=10;
        if(f2)
        {
            for(int i=1;i<=a;i++)
                dp[i]--;
            for(int i=0;i<=9;i++)
                dp[i]-=le;
        }//末位
        else
        {
            if(a!=0)
                dp[0]-=le*sl;

            for(int i=1;i<a;i++)
                dp[i]-=(le+1)*sl;

            if(a!=0)
                dp[a]-=(le*sl+lt+1);
            else
            {
                dp[a]-=((le-1)*sl+lt+1);
            }

            for(int i=a+1;i<=9;i++)
                dp[i]-=le*sl;

        }//中间位

        lt+=sl*a;sl*=10;
        f2=false;
    }
}

int main()
{

    scanf("%lld%lld",&le,&ri);
    le--;
    solve();
    for(int i=0;i<=9;i++)
    {
        printf("%lld\n",dp[i]);
    }

    return 0;
}
/*
2019/11/11
方法2
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

ll dp1[25],dp2[25];

void dfs(ll x,ll sx,ll ans[])
{
    int a=x%10;x/=10;ll t=x;
    for(int i=1;i<=a;i++) ans[i]+=sx;
    for(int i=0;i<10;i++) ans[i]+=sx*x;
    while(t)
    {
        ans[t%10]+=sx*(a+1);
        t/=10;
    }
    if(x)
        dfs(x-1,sx*10,ans);
}

int main()
{
    ll le,ri;
    scanf("%lld%lld",&le,&ri);
    le--;
    dfs(ri,1,dp1);dfs(le,1,dp2);
    for(int i=0;i<10;i++) printf("%lld\n",dp1[i]-dp2[i]);

    return 0;
}

1100 斜率最大

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1100

Hint(437ms):O(n^2)暴力可过,很久以前写的代码懒得重写了当时maxn初始化设大了一直wa,现在debug完ac

Hint(优化,31ms):可以把O(n^2)优化到O(ans+nlogn)(虽然差不多是这个意思,但这个复杂度是我在胡说八道,没有这么求复杂度的23333),咳,实际上我们很容易发现取相邻两个点最优:

←以及有一种需要考虑的特殊情况(同直线多解)

提供一个数据:

INPUT:

5
1 2
2 4
3 6
4 2
5 4

OUTPUT:

1 2

1 3

2 3

4 5

/*
2019/11/24
暴力
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

struct P
{
    ll x,y;
    int f;
}point[10005];

bool cmp(P a,P b)
{
    if(a.x<=b.x) return true;
    else return false;
}

vector<pair<P,P> > v;

bool cmp2(pair<P,P> a,pair<P,P> b)
{
    if(a.first.x<b.first.x) return true;
    else return false;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&point[i].x,&point[i].y);
        point[i].f=i;
    }
    sort(point+1,point+1+n,cmp);
    double maxn=-2e10;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            //cout<<'i'<<i<<' '<<'j'<<j<<endl;
            double k=(point[j].y-point[i].y)*1.0/(point[j].x-point[i].x);
            //cout<<k<<endl;
            //cout<<maxn<<endl;
            if(k>=maxn)
            {
                if(k>maxn) v.clear();
                pair<P,P> it;
                it.first=point[i];
                it.second=point[j];
                v.push_back(it);
                maxn=k;
            }
        }
    }
    //sort(v.begin(),v.end(),cmp2);
    //cout<<v.size()<<endl;
    for(int i=0;i<v.size();i++)
        printf("%d %d\n",v[i].first.f,v[i].second.f);

    return 0;
}
/*
2019/11/24
优化
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

struct P
{
    ll x,y;
    int f;
} point[10005];

bool cmp(P a,P b)
{
    if(a.x<=b.x) return true;
    else return false;
}

vector<pair<P,P> > v;

bool cmp2(pair<P,P> a,pair<P,P> b)
{
    if(a.first.x<b.first.x) return true;
    else return false;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld%lld",&point[i].x,&point[i].y);
        point[i].f=i;
    }
    sort(point+1,point+1+n,cmp);
    double maxn=-2e10;
    int step=0;
    for(int i=1; i<=n-1; i++)
    {
        double k=(point[i+1].y-point[i].y)*1.0/(point[i+1].x-point[i].x);
        if(k>=maxn)
        {
            pair<P,P> it;
            if(k>maxn)
            {
                v.clear();
                step=1;
            }
            else
            {
                for(int j=1;j<=step;j++)
                {
                    it.first=point[i-j];
                    it.second=point[i+1];
                    v.push_back(it);
                }
                step++;
            }
            it.first=point[i];
            it.second=point[i+1];
            v.push_back(it);
            maxn=k;
        }
        else step=0;
    }
    sort(v.begin(),v.end(),cmp2);
    //cout<<v.size()<<endl;
    for(int i=0; i<v.size(); i++)
        printf("%d %d\n",v[i].first.f,v[i].second.f);

    return 0;
}

1103 N的倍数

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1103

Hint:前缀和、抽屉原理

/*
2019/11/6
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

ll a[50005];
int vis[50005];

int main()
{
    int n;
    ll sum=0;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%I64d",a+i);
    }
    for(int i=1; i<=n; i++)
    {
        sum+=a[i];
        sum%=n;
        if(sum==0)
        {
            printf("%d\n",i);
            for(int j=1; j<=i; j++)
            {
                printf("%I64d\n",a[j]);
            }
            break;
        }
        if(vis[sum]!=0)
        {
            printf("%d\n",(i-vis[sum]));
            for(int j=vis[sum]+1; j<=i; j++)
            {
                printf("%I64d\n",a[j]);
            }
            break;
        }
        vis[sum]=i;
    }

    return 0;
}

1125 交换机器的最小代价

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1125

Hint:贪心(环内最小 or 环外最小)

/*
2019/11/26
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

pair<ll,int> wi[50005];
int f[50005];
int tf[50005];
bool vis[50005];

bool cmp(int x,int y)
{
    if(wi[x].first<wi[y].first)
        return true;
    else if(wi[x].first==wi[y].first)
    {
        return wi[x].second<wi[y].second;
    }
    else
        return false;
}

int main()
{
    int n;
    scanf("%d",&n);
    ll mint=1e9;
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&wi[i].first);
        mint=min(mint,wi[i].first);
        wi[i].second=i;
        f[i]=i;
    }
    sort(f+1,f+n+1,cmp);
    for(int i=1; i<=n; i++)
        tf[f[i]]=i;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        if(tf[i]!=i && !vis[tf[i]])
        {
            int j=tf[i];
            int step=0;ll minn=1e9;
            while(!vis[j])
            {
                ans+=wi[f[j]].first;
                step++;
                minn=min(minn,wi[f[j]].first);
                vis[j]=true;
                j=tf[j];
            }
            ll t1=minn*(step-2),t2=mint*(step-1)+mint*2+minn;
            if(t1<t2)
                ans+=t1;
            else
                ans+=t2;
        }
    }
    printf("%lld\n",ans);

    return 0;
}

1132 覆盖数字的数量

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1132

Hint:数学瞎推(考虑之间空出来的数有多少个,等差数列求和)、分类

/*
2019/12/7
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll a,b,x,y;
        scanf("%lld%lld%lld%lld",&a,&b,&x,&y);
        if(a==b)
        {
            ll hmx=(x-1)/a;
            ll hmy=y/a;
            printf("%lld\n",hmy-hmx);
        }
        else
        {
            ll k=a/(b-a);
            if(a%(b-a)!=0) k++;
            if(k<2)
            {
                ll ans=y-x+1;
                if(x<a)
                {
                    ans-=(a-x);
                }
                ans=max(ans,0LL);
                printf("%lld\n",ans);
            }
            else
            {
                ll ans=y-x+1;
                if(x<a)
                {
                    ans-=(a-x);
                }
                ll st=x/a;
                st=max(st,1LL);
                ll en=y/b;
                ll edge=a/(b-a);
                if(a%(b-a)!=0) edge++;
                en=min(en,edge);
                st++;
                if(en>=st)
                {
                    //st++;
                    ll sum1=0;
                    if((st+en)%2==0)
                        sum1=((st+en)/2)*(en-st+1);
                    else
                        sum1=((en-st+1)/2)*(st+en);
                    ll sum2=sum1-(en-st+1);
                    sum1*=a;
                    sum2*=b;
                    //cout<<sum1-sum2<<endl;
                    ans-=(sum1-sum2-1);
                }
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

1191 消灭兔子

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1191

Hint:贪心(血量高→血量低)、优先队列

/*
2019/11/29
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

int b[100005];
priority_queue<int,vector<int>,greater<int> > pq;
pair<int,int> p[100005];//first:p second:d

bool cmp(int x,int y)
{
    return x>y;
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&b[i]);
    }
    sort(b+1,b+n+1,cmp);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&p[i].first,&p[i].second);
    }
    sort(p+1,p+m+1);


    int step=m;
    ll ans=0;
    bool flag=false;

    for(int i=1;i<=n;i++)
    {
        int minn=1000001;
        while(step>=1 && p[step].first>=b[i])
        {
            if(p[step].second<=minn)
            {
                if(minn!=1000001)
                {
                    pq.push(minn);
                }
                minn=p[step].second;
            }
            else
            {
                int x=p[step].second;
                pq.push(x);
            }
            step--;
        }
        if(!pq.empty())
        {
            int mint=pq.top();
            if(mint<minn)
            {
                pq.pop();
                if(minn!=1000001)
                    pq.push(minn);
                minn=mint;
            }
        }

        if(minn==1000001)
        {
            flag=true;
            break;
        }
        ans+=minn;
    }
    if(flag)
        printf("No Solution\n");
    else
        printf("%lld\n",ans);

    return 0;
}

1262 扔球

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1262

Hint:数论、考虑间隔点

/*
2019/12/3
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long


int main()
{
    int x;
    scanf("%d",&x);
    x++;
    int ans=x;
    if(x%2==0)
    {
        while(x%2==0)
            x/=2;
        ans/=2;
    }
    for(int i=3;i<=sqrt(x);i+=2)
    {
        if(x%i==0)
        {
            while(x%i==0)
                x/=i;
            ans/=i;ans*=(i-1);
        }
    }
    if(x>2)
    {
        ans/=x;ans*=(x-1);
    }
    printf("%d\n",ans);
    return 0;
}

1419 最小公倍数挑战

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1419

Hint:推规律(相邻两奇数互质、相邻两数互质、偶奇互质情况判断)

/*
2019/12/4
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

int main()
{
    int n;
    scanf("%d",&n);
    if(n<=2) printf("%d\n",n);
    else if(n%2) printf("%lld\n",(ll)n*(n-1)*(n-2));
    else if(n%3) printf("%lld\n",(ll)n*(n-1)*(n-3));
    else
    {
        printf("%lld\n",(ll)(n-1)*(n-2)*(n-3));
    }

    return 0;
}

1445 变色DNA

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=1445

Hint:最短路(暂时只写了floyd版,之后有时间再补上dijkstra,应该都没差因为数据很小。。)

/*
2019/11/25
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

int dis[55][55];
char pic[55][55];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%s",pic[i]);
            for(int j=0; j<n; j++)
            {
                dis[i][j]=1e4;
                if(i==j)
                    dis[i][j]=0;
            }
        }
        for(int i=0; i<n; i++)
        {
            int step=0;
            for(int j=0; j<n; j++)
            {
                if(pic[i][j]=='Y')
                {
                    dis[i][j]=step++;
                }
            }
        }
        for(int k=0; k<n; k++)
        {
            for(int i=0; i<n; i++)
            {
                for(int j=0; j<n; j++)
                {
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
                }
            }
        }
        printf("%d\n",(dis[0][n-1]==1e4?dis[0][n-1]=-1:dis[0][n-1]));
    }
    return 0;
}

2200 接水问题二

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=2200

Hint:贪心、推公式

/*
2019/12/10
*/
#include<bits/stdc++.h>

using namespace std;

#define ll long long

struct Point
{
    int x,y;
    double a;
    bool operator <(const Point & t) const
    {
        return a>=t.a;
    }
} po[100005];

int main()
{
    int n;
    scanf("%d",&n);
    int cnt=0;
    for(int i=1; i<=n; i++)
    {
        int xx,yy;
        scanf("%d%d",&xx,&yy);
        if(xx==0||yy==0) continue;
        ++cnt;
        po[cnt].x=xx;
        po[cnt].y=yy;
        po[cnt].a=1.0*po[cnt].x/po[cnt].y;

    }
    sort(po+1,po+cnt+1);
    ll suma=0,ans=0;
    for(int i=1; i<=cnt; i++)
    {
        suma+=po[i].y;
        ans+=suma*po[i].x;
    }
    printf("%lld\n",ans);

    return 0;
}

2463 旅行

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=2463

Hint:贪心、搜索+剪枝(注意m只可能为n-1或n,即不存在环/存在一个环)

(今天晚上代码写得感觉很乱,假如我还记得的话再回来重写一遍。。

/*
2019/12/2
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

vector<int> v[5005];
int st[5005];
int vt[5005];
int top=0;
int tot=0;
int pre[5005];
bool vis[5005];
int n,m;
int xx=0,yy=0;
int step=1;
int ans[5005];
bool f=false;
bool flag=false;

void dfs(int x)
{
    if(!vis[x])
    {
        if(x<ans[step])
            flag=true;
        if(x>ans[step]&&!flag)
        {
            return;
        }
        ans[step]=x;
    }
    if(step==n)
    {
        return;
    }
    vis[x]=true;
    int minn=n+1;
    int hm=0;
    for(int i=0;i<v[x].size();i++)
    {
        int y=v[x][i];
        if(!(y==yy&&x==xx)&&!(y==xx&&x==yy)&&!vis[y])
        {
            minn=min(minn,y);
            hm++;
        }
    }
    if(hm!=0)
    {
        step++;
        pre[minn]=x;
        dfs(minn);
    }
    else
    {
        dfs(pre[x]);
    }
}

void dfs2(int x)
{
    if(f) return;
    st[++top]=x;
    vis[x]=true;
    for(int i=0;i<v[x].size();i++)
    {
        int y=v[x][i];
        if(y==pre[x]) continue;
        if(!vis[y])
        {
            pre[y]=x;
            dfs2(y);
        }
        else
        {
            //cout<<x<<' '<<y<<"!!!"<<endl;
            for(int j=top;st[j]!=y;j--)
            {
                vt[++tot]=st[j];
            }
            vt[++tot]=y;
            f=true;
            break;
        }
    }
    if(f) return;
    top--;
    vis[x]=false;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    for(int i=1;i<=n;++i)
        ans[i]=n+1;
    if(m==n-1)
    {
        dfs(1);
        for(int i=1;i<=n;++i)
            printf("%d%c",ans[i],(i==n)?'\n':' ');
    }
    else
    {
        vis[1]=true;
        dfs2(1);
        vt[tot+1]=vt[1];
        for(int i=1;i<=tot;++i)
        {
            xx=vt[i];yy=vt[i+1];
            memset(vis,false,sizeof(vis));
            flag=false;
            step=1;
            dfs(1);
        }
        for(int i=1;i<=n;++i)
            printf("%d%c",ans[i],(i==n)?'\n':' ');
    }
    return 0;
}

2488 矩形的面积

题目链接:

http://www.51nod.com/Challenge/Problem.html#problemId=2488

Hint:随便画一画就知道有交集是啥情况了

/*
2019/11/19
*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long

int main()
{
    ll a,b,c,d,e,f,g,h;
    scanf("%lld%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&g,&h);
    if((a<=g&&b<=h&&e<=c&&f<=d)||(a>=g&&b>=h&&e>=c&&f>=d))
    {
        ll lx,ly,rx,ry;
        lx=max(a,e);ly=max(b,f);
        rx=min(c,g);ry=min(d,h);
        ll ans=(c-a)*(d-b);
        ans-=(ry-ly)*(rx-lx);
        ans+=(g-e)*(h-f);
        printf("%lld\n",ans);
    }
    else
    {
        ll ans=(c-a)*(d-b)+(g-e)*(h-f);
        printf("%lld\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值