• NOI 2011


    [NOI2011]兔农

     暴力O(n)递推就有75。。。记下模k的结果和模g的结果,遇到模k等于1两个都减一。

    注意滚动。

    CODE:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=1e7+10;
    long long f[5],g[5];
    long long n,k,mod; 
    
    int main()
    {
        scanf("%lld%lld%lld",&n,&k,&mod);
        f[1]=f[2]=1;
        g[1]=g[2]=1;
        for(long long i=3;i<=n;i++)
        {
            f[3]=(f[1]+f[2])%k;
            g[3]=(g[1]+g[2])%mod;
            if(f[3]%k==1) g[3]--,f[3]=0;
            g[3]=(g[3]+mod)%mod;
            g[1]=g[2],g[2]=g[3];
            f[1]=f[2],f[2]=f[3];
        }
        if(n<3) g[3]=g[1];
        printf("%lld",g[3]%mod);
        return 0;
    }
    View Code

    [NOI2011]智能车比赛

    很精彩的一道题。

    可以发现所有的拐点都在矩形的四个角,有DP:

    这个DP用spfa来转移,只不过在扩展队首的时候,要判断是否能够到达。

    现在就变成了如何在最多O(n)时间内判断两点是否可以直接互相达到。

    对于每个点,扩展的时候,维护一个high,一个low,表示张角的限制,因为已经按照x排过序了,所以通过叉积的计算就可以更新啦。

    注意high只能用矩形的2个上角更新,low同理。

    判断的时候也用叉积。

    CODE:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <cmath>
    using namespace std;
    const int maxn=9003;
    struct Line
    {
        double x,y;
    }line[maxn],s,t;
    int n,st,vis[maxn];
    double v,dis[maxn];
    
    double DIS(Line a,Line b) 
    {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    
    double cross(Line o,Line a,Line b) 
    {
        double x1=a.x-o.x,y1=a.y-o.y;
        double x2=b.x-o.x,y2=b.y-o.y;
        return x1*y2-x2*y1;
    }
    
    bool check(int up,int low,Line a,Line b) 
    {
        return !((up && cross(a,line[up],b)>0) || (low && cross(a,line[low],b)<0));
    }
    
    
    inline void spfa()
    {
        queue<int> q;
        for(int i=st;i<=n;i++) dis[i]=1e9;
        dis[st]=0;
        vis[st]=1;
        q.push(st);
        while(!q.empty())
        {
            int tt=q.front();
            q.pop();
            vis[tt]=0;
            int up=0,low=0;
            for(int i=tt+1;i<=n;i++)
            {
                if(check(up,low,line[tt],line[i]))
                {
                    if(dis[tt]+DIS(line[tt],line[i])<dis[i])
                    {
                        dis[i]=dis[tt]+DIS(line[tt],line[i]);
                        if(!vis[i]) vis[i]=1,q.push(i); 
                    }
                }
                if(((i-1)%4+1) & 1 && (!up || cross(line[tt],line[up],line[i])<=0)) up=i;
                else if(!(((i-1)%4+1)&1) && (!low || cross(line[tt],line[low],line[i])>=0)) low=i;
                if(up && low && cross(line[tt],line[up],line[low])>0) break;
            }    
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&line[i*4-2].x,&line[i*4-2].y,&line[i*4-1].x,&line[i*4-1].y);
            line[i*4-3]=(Line){line[i*4-2].x,line[i*4-1].y};
            line[i*4]=(Line){line[i*4-1].x,line[i*4-2].y};        
        }
        n=n*4;
        scanf("%lf%lf",&s.x,&s.y);
        scanf("%lf%lf",&t.x,&t.y);
        scanf("%lf",&v);
        if(s.x>t.x) swap(s,t);
        for(;n;n--) if(line[n].x<=t.x) break;
        line[++n]=t;
        for(st=1;st<=n;st++) if(line[st].x>=s.x) break;
        line[--st]=s;
        spfa();
        printf("%.10lf",dis[n]/v);
        return 0;
    }
    View Code

    [NOI2011]兔兔与蛋蛋游戏

    搜索75/ 非常精彩的一道题

    以空格为起点将棋盘黑白染色,将空格染成黑色,这样相邻两个点的颜色总是不一样的,等效于在二分图的两侧来回走。

    那么一般的,任意给一个棋局,都可以看成一个已经走过一部分的二分图(不可能走重复的格子,因为是黑白交替走),考虑给定二分图先手是否必胜。

    二者相当于走一个交错路(最后一步一定是先手走),由于最大匹配的交错路可以使得后手无路可走,所以我们开始关注最大匹配。

    如果此图中的最大匹配独一无二,先手必胜;

    不然就有可能被后手引上"歧途",从而无路可走。

    如何判断一个点是否是非必需点?

    • 如果当前点本来就没有匹配的点,显然不在。
    • 如果当前点所匹配的点在删去当前点后,能够继续增广,就说明当前点不一定在最大匹配上,否则一定在。

     好好意会吧。。。

    CODE:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=50003;
    const int maxm=5e6+10;
    struct point
    {
        int x,y;
        int to,nxt;
    }edge[maxm]; 
    int n,m,k,bx,by,cnt,tot;
    int map[203][203],ban[maxn],match[maxn];
    int vis[maxn],viss[203][203],head[maxn],ans[maxn];
    char ss[maxn];
    int derx[]={0,0,0,1,-1};
    int dery[]={0,1,-1,0,0};
    
    inline void add(int u,int v)
    {
        tot++;
        edge[tot].nxt=head[u];
        edge[tot].to=v;
        head[u]=tot;
    }
    
    inline int iu(int x,int y)
    {
        return (x-1)*m+y;
    }
    
    inline void Bfs()
    {
        queue<point> q;
        memset(viss,0,sizeof(viss));
        q.push((point){bx,by,0,0});
        while(!q.empty())
        {
            point e=q.front();
            q.pop();
            for(int i=1;i<=4;i++)
            {
                int xx=e.x+derx[i],yy=e.y+dery[i];
                if(xx<1 || xx>n || yy<1 || yy>m || !(map[e.x][e.y]^map[xx][yy])) continue;
                add(iu(e.x,e.y),iu(xx,yy));    
                add(iu(xx,yy),iu(e.x,e.y));    
                if(!viss[xx][yy])
                {
                    q.push((point){xx,yy,0,0});
                    viss[xx][yy]=1;
                }
            }
        }
    }
    
    inline bool dfs(int x)
    {
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(vis[v] || ban[v]) continue;
            vis[v]=1;
            if(!match[v] || dfs(match[v]))
            {
                match[v]=x;
                match[x]=v;
                return true;
            }
        }
        return false;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",ss+1);
            for(int j=1;j<=m;j++)
            {
                if(ss[j]=='.')
                {
                    bx=i,by=j;
                    map[i][j]=1;
                }
                else if(ss[j]=='X') map[i][j]=1;
                else if(ss[j]=='O') map[i][j]=0;
            }
        }
        Bfs();
        for(int i=1;i<=n*m;i++)
            if(!match[i])
            {
                memset(vis,0,sizeof(vis));
                dfs(i);
            }
        scanf("%d",&k);
        for(int i=1;i<=k;i++)
        {
            int cn=iu(bx,by),a1=0,a2=0;
            ban[cn]=1;
            if(match[cn])
            {
                int op=match[cn];
                match[op]=0; match[cn]=0;
                memset(vis,0,sizeof(vis));
                a1=!dfs(op);
            }
            else a1=0;
            scanf("%d%d",&bx,&by);     
            cn=iu(bx,by);
            ban[cn]=1;
            if(match[cn])
            {
                int op=match[cn];
                match[op]=0; match[cn]=0;
                memset(vis,0,sizeof(vis));
                a2=!dfs(op);
            }
            else a2=0;
            if(a1 && a2) ans[++cnt]=i;
            scanf("%d%d",&bx,&by);
        }
        printf("%d
    ",cnt);
        for(int i=1;i<=cnt;i++) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code

    [NOI2011]道路修建

    一遍dfs就行了,NOIP之前做的题 o_O

    //long long 害死人 
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int maxn=1e6+10;
    struct point
    {
        int to;
        long long w;
        int nxt;
    }edge[maxn<<1];
    int n,tot;
    int head[maxn],S[maxn];
    long long ans=0;
    
    inline void add(int u,int v,long long w)
    {
        tot++;
        edge[tot].to=v;
        edge[tot].nxt=head[u];
        edge[tot].w=w;
        head[u]=tot;
    }
    
    inline void dfs(int x,int fa)
    {
        S[x]=1;
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v!=fa)
            {
                dfs(v,x);
                ans+=(long long)abs(n-S[v]*2)*edge[i].w;
                S[x]+=S[v];
            }    
        }
    }
    
    int main()
    {
        cin>>n;
        for(int i=1;i<=n-1;i++)
        {
            int a,b;
            long long w;
            scanf("%d%d%lld",&a,&b,&w);
            add(a,b,w);
            add(b,a,w);
        }
        dfs(1,0);
        printf("%lld",ans);
        return 0;
    }
    View Code

  • 相关阅读:
    微信支付退款部分代码
    Raspberry PI 点亮LED
    Raspberry PI 摄像头
    RaspberryPI 3B系统烧录
    MySQL基础使用
    MySQL数据库管理系统概述
    Eclipse创建JAVA项目
    Brup Suite拦截https请求
    Github 第一个仓库
    python os模块主要函数
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/9120053.html
Copyright © 2020-2023  润新知