ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Contest2156 - 2019-3-7 高一noip基础知识点 测试2

2019-03-09 11:03:52  阅读:295  来源: 互联网

标签:知识点 return noip int dfs getsum 2019 numa numc


传送门

预计得分:100+70+100+50=320

实际得分100+63+77+30=270

Ctrl_C+Ctrl_V时不要粘贴翻译的,直接粘原文,

In a single line of the output print an integer — the maximum loyalty among all paths from the first node to the n-th one. If such paths do not exist or the maximum loyalty equals 0, print in a single line "Nice work, Dima!" without the quotes. 输出能从1出发到n的总数值数,如果没有,输出“Nice work,Dima!”
两个判错之间在逗号前差了一个空格 QAQ

 

T1

dfs+剪枝

对于搜到的一组(a,b,c),将a*t^2+b*t+1(t>=20)标记,下一次再经过时就直接return

代码

#include<bits/stdc++.h>
using namespace std;
int n,k;
int numa,numb,numc,ans[100100],cnt;
int vis[100100];
bool sum[100100],pd;
inline int getsum(int a,int b,int c){return a*441+b*21+c;}
void dfs(int deep,int a,int b,int c)
{
    if(a>numa||b>numb||c>numc)return;
    //cout<<a<<"!"<<b<<"!"<<c<<endl;system("pause");
    sum[a*441+b*21+c]=1;
    if(!a)
    {
        if(!vis[c])ans[++cnt]=c;
        //cout<<c<<endl;
        vis[c]=1;   
    }
    if(a)
    {
        int k=getsum(0,a+b,c),kk=getsum(a+b-numb,numb,c);
        if(a+b<=numb&&!sum[k])sum[k]=1,dfs(deep+1,0,a+b,c);
        else
        {
            if(!sum[kk]&&a+b>numb) sum[kk]=1,dfs(deep+1,a+b-numb,numb,c);
        }
        k=getsum(0,b,a+c);kk=getsum(a+c-numc,b,numc);
        if(a+c<=numc&&!sum[k])sum[k]=1,dfs(deep+1,0,b,a+c);
        else
        {
            if(!sum[kk]&&a+c>numc) sum[kk]=1,dfs(deep+1,a+c-numc,b,numc);
        }
    }
    if(b)
    {
        int k=getsum(a+b,0,c),kk=getsum(numa,a+b-numa,c);
        if(a+b<=numb&&!sum[k])sum[k]=1,dfs(deep+1,a+b,0,c);
        else
        {
            if(!sum[kk]&&a+b>numa)sum[kk]=1,dfs(deep+1,numa,a+b-numa,c);
        }
        k=getsum(a,0,b+c);kk=getsum(a,b+c-numc,numc);
        if(b+c<=numc&&!sum[k])sum[k]=1,dfs(deep+1,a,0,b+c);
        else
        {
            if(!sum[kk]&&b+c>numc) sum[kk]=1,dfs(deep+1,a,b+c-numc,numc);
        }
    }
    if(c)
    {
        int k=getsum(a+c,b,0),kk=getsum(numa,b,a+c-numa);
        if(a+c<=numa&&!sum[k])sum[k]=1,dfs(deep+1,a+c,b,0);
        else
        {
            if(!sum[kk]&&a+c>numa) sum[k]=1,dfs(deep+1,numa,b,a+c-numa);
        }
        k=getsum(a,b+c,0);kk=getsum(a,numb,b+c-numb);
        if(b+c<=numb&&!sum[k])sum[k]=1,dfs(deep+1,a,b+c,0);
        else
        {
            if(!sum[kk]&&b+c>numb) sum[kk]=1,dfs(deep+1,a,numb,b+c-numb);
        }
    }
}
int main()
{
    scanf("%d%d%d",&numa,&numb,&numc);
    dfs(1,0,0,numc);
    sort(ans+1,ans+cnt+1);
    for(int i=1;i<=cnt;i++)printf("%d ",ans[i]);
}
T1

 

T2

容易想到区间一定是连续的

但是这种容易想到的一般都是错的

例如数据

3 3

1 2 1 2

2 3 1 10000

1 2 7 8

显然区间不是连续的。

于是,我们的思路是枚举下界,二分上界,用dfs或是并查集维护1-n的连通

dfs太难打了,david-alwal太懒了,所以用了并查集

#include<bits/stdc++.h>
using namespace std;
struct edge
{
    int from,to,nxxt,le,ri;
}e[100100<<1];
int head[100100],n,m,cnt,t,maxx=-1,ans;
inline void addedge(int u,int v,int l,int r)
{
    cnt++;
    e[cnt].from=u;
    e[cnt].le=l;
    e[cnt].ri=r;
    e[cnt].to=v;
    e[cnt].nxxt=head[u];
    head[u]=cnt;
}
int lef[100100],num;
int f[100100];
int getroot(int x){if(x!=f[x])f[x]=getroot(f[x]);return f[x];}
inline int check(int l,int r)
{
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=cnt;i++)
    {
        int from=e[i].from,to=e[i].to;
        int le=e[i].le,ri=e[i].ri;
        if(le<=l&&ri>=r)
        {
            int f1=getroot(from);
            int f2=getroot(to);
            if(f1!=f2)f[f1]=f2;
        }
    }
    if(getroot(1)==getroot(n))return 1;return 0;
}
void ef(int l,int r,int k)
{
    if(l==r)
    {
        while(k<=l&&check(k,l)==0)l--;
        ans+=l-k+1;
        if(l>=k)
            t=max(t,l);
        return;
    }
    int mid=(l+r)>>1;
    if(check(k,mid+1))ef(mid+1,r,k);
    else ef(l,mid,k);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,l,r;
        scanf("%d%d%d%d",&u,&v,&l,&r);
        addedge(u,v,l,r);
        addedge(v,u,l,r);
        lef[++num]=l;
        maxx=max(maxx,r);
    }
    sort(lef+1,lef+num+1);
    for(int i=1;i<=num;i++)
    {
        if(lef[i]<=t)continue;
        else ef(lef[i],maxx,lef[i]);
    }
    if(ans<=0)puts("Nice work, Dima!");
    else printf("%d",ans);
}
T2

 

T3

个人认为是最简单的一道题

一个BFS就可以解决

下标不能为负数!!

上代码

#include<bits/stdc++.h>
using namespace std;
int n,k;
queue<int>q;
int num[500100],vis[500100];
int maxx;
int main()
{
    scanf("%d%d",&n,&k);
    //if(n>=k){printf("%d",n-k);return 0;}
    maxx=max(n,k)<<1;
    q.push(n);
    vis[n]=1;
    while(!q.empty())
    {
        int now=q.front();q.pop();
        if(now==k)break;
        if((!vis[now+1])&&(now+1<maxx))
        {
            num[now+1]=num[now]+1;
            vis[now+1]=1;
            q.push(now+1);
        }
        if((!vis[now<<1])&&((now<<1)<maxx))
        {
            num[now<<1]=num[now]+1;
            vis[now<<1]=1;
            q.push(now<<1);
        }
        if((!vis[now-1])&&(now-1>=0))
        {
            num[now-1]=num[now]+1;
            vis[now-1]=1;
            q.push(now-1);
        }
    }
    printf("%d",num[k]);
}
T3

T4

dfs+剪枝

剪枝1:,可行性剪枝:对于一个点(x,y),如果它左上角的颜色加上它走到底下的格子数大于k,就return 0

剪枝2,对称性剪枝:例如我们当前填到了某个格子,我们记录一下整个矩阵已使用的颜色,例如3,5都还没用,那么这个格子填上3或5,两者最终算出的方案数是相同的,这样我们就可以只计算3的方案数,5的直接加上3的就可以了。

用状压存状态特别方便

没有单独讲状态压缩的博客,只有讲状压DP的,大家就只看状压那部分的吧 详解状压 David-alwal太懒了

上代码

#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
int m,n,k,a[101][101],f[101][101],num[101];
//f数组存状压之后的状态,例如5个颜色,f[x][y]=13的话, 
//因为13(10)=01101(2),这就代表了(x,y)左上角的点取了2,3,5,没有取1,4 
int dfs(int x,int y)
{
    if(y>m)x++,y=1;
    if(x>n)return 1;
    int ret=0,d=-1,now=f[x-1][y]|f[x][y-1],c=0;
    for(int i=now;i;i-=i&-i)c++;
    if(m+n-x-y+1>k-c)return 0;//剪枝1 
    int can=(~now)&((1<<k)-1);//能取的 
    for(int i=can;i;i-=i&(-i))//提取每一位二进制 
    {
        int temp=i&(-i);
        int t=log(temp+0.5)/log(2)+1;
        if(a[x][y]==0||a[x][y]==t)
        {
            f[x][y]=now|temp;
            num[t]++;
            if(num[t]==1)//剪枝2 
            {
                if(d==-1)d=dfs(x,y+1);
                ret+=d;
            }
            else ret+=dfs(x,y+1);
            ret%=mod;
            num[t]--;
        }
    }
    return ret;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    if(n+m-1>k){puts("0");return 0;}//剪枝1 
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
            if(a[i][j])num[a[i][j]]++;//统计数量 
        }
    printf("%d",dfs(1,1)%mod);
}
T4

 

标签:知识点,return,noip,int,dfs,getsum,2019,numa,numc
来源: https://www.cnblogs.com/yanghaokun/p/10499697.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有