zoukankan      html  css  js  c++  java
  • 【考试反思】联赛模拟测试9

    凯爹怒 (mathbb{AK}) 钛聚辣

    集训很长时间了,一直以为没有怎么挂分,结果今天直接打脸,再加上两道原题,人直接爆炸。

    是状态的问题吗?不,就是菜吧。

    T1: 60 ( ightarrow) 20

    T2: 60 ( ightarrow) 15

    T3: 50 ( ightarrow) 30

    T4: 100 ( ightarrow) 20

    T1:嚎叫响彻在贪婪的厂房

    考场上没想到用 set然后 (O(n^2log n)) 暴力排序的,莫名其妙挂了。


    根据题目名字的提示我们可以想到贪心。

    可以想到不合法的情况就是 (gcd=1) 或相等,其他直接和前面合并即可。利用 set 做到 (O(nlog n))

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    int n,ans;
    int a[maxn];
    set<int> s;
    
    inline int read(){
        int x=0;bool fopt=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
        return fopt?x:-x;
    }
    
    int gcd(int x,int y){
        if(y==0)return x;
        return gcd(y,x%y);
    }
    
    int main(){
    #ifndef LOCAL
        freopen("factory.in","r",stdin);
        freopen("factory.out","w",stdout);
    #endif
        n=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        int i=1;
        while(i<=n){
            if(i==n){
                ans++;break;
            }
            int d=abs(a[i+1]-a[i]);
            if(d==0||d==1){
                ans++;i++;continue;
            }
            s.insert(a[i]);s.insert(a[i+1]);
            int j;
            for(j=i+2;j<=n;j++){
                if(s.find(a[j])!=s.end())break;
                d=gcd(d,abs(a[j]-*s.begin()));
                if(d==1)break;
                s.insert(a[j]);
            }
            i=j;ans++;s.clear();
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    T2:征途堆积出友情的永恒

    (O(n^2)) 的暴力很好写,但是人傻了,忘记可以从出发点直接开到现在,而且特判的分数也没写全。

        memset(f,0x3f,sizeof(f));
        f[0]=0;//删掉60->15,人傻了
        f[1]=max(b[0],a[1]);
        for(register int i=2;i<=n;i++)
            for(register int j=i;j>=0&&i-j<=K;j--)
                f[i]=min(f[i],f[j]+max(b[j],sum[i]-sum[j]));
        ans=f[n];
    

    简单的转移方程写出来之后,根据题目名字的提示我们想到了用堆优化转移。

    对于 (j)(f[j]+b[j])(f[j]-sum[j]) 都是确定的。

    那么就关于这两个东西维护两个小根堆。同时要注意因为在 (b[j]>sum[i]-sum[j]) 时第一个堆里的元素才会合法,所以首先把所有堆 1 里不合法的 pop,但要把它推入堆 2。

    上面那个操作之前,之后,都要 pop 在距离上 (>k) 的点。如果之后不 pop ,会错一个点。

    while 循环很带感

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=5e5+10;
    int n,K;
    long long ans;
    int a[maxn],b[maxn];
    long long sum[maxn],f[maxn];
    
    struct Node{
        int x;
        long long w;
        friend inline bool operator <(register const Node& A,register const Node& B){
            return A.w>B.w;
        }
    };
    
    inline int read(){
        int x=0;bool fopt=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
        return fopt?x:-x;
    }
    
    priority_queue<Node> q1,q2;
    
    int main(){
    #ifndef LOCAL
        freopen("empire.in","r",stdin);
        freopen("empire.out","w",stdout);
    #endif
        n=read();K=read();
        for(int i=1;i<=n;i++){
            a[i]=read();
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=1;i<=n;i++)
            b[i-1]=read();
        memset(f,0x3f,sizeof(f));
        f[0]=0;
        for(int i=1;i<=n;i++){
            q1.push((Node){i-1,f[i-1]+b[i-1]});
            while(!q1.empty()){
                Node x=q1.top();
                if(x.x>=i-K)break;
                q1.pop();
            }
            while(!q2.empty()){
                Node x=q2.top();
                if(x.x>=i-K)break;
                q2.pop();
            }
            while(!q1.empty()){
                Node x=q1.top();
                if(x.w>f[x.x]+sum[i]-sum[x.x])break;
                q1.pop();q2.push((Node){x.x,f[x.x]-sum[x.x]});
            }
            while(!q1.empty()){
                Node x=q1.top();
                if(x.x>=i-K)break;
                q1.pop();
            }
            while(!q2.empty()){
                Node x=q2.top();
                if(x.x>=i-K)break;
                q2.pop();
            }
            long long temp=0x3f3f3f3f3f3f3f3f;
            if(!q1.empty())temp=min(temp,q1.top().w);
            if(!q2.empty())temp=min(temp,q2.top().w+sum[i]);
            f[i]=temp;
        }
        printf("%lld
    ",f[n]);
        return 0;
    }
    

    T3:小奇的仓库

    这个人更傻了,之前还写过题解的。

    基础的换根 (DP) 的分怎么没拿到呢?快和小编来看一看吧。

    void dfs2(int u,int fa){
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fa)continue;
            f[v]=f[u]+(n-siz[v])*e[i].w-siz[v]*e[i].w;
            dfs2(v,u);//考场没写这句
        }
    }
    

    由于样例只有一层,所以我并没有看出来我写挂了:D。

    题解

    注意其算的是异或后的差值,所以最后统一修改是正确的。可以手模一下。

    T4:放置机器人

    二分图练习里就这道题没写:D。人都傻掉了。

    考场上拆行拆列都写了,结果没想到最后打败我的是匈牙利的板子忘掉了。事实上,还是对匈牙利的本质没有弄清。

    bool vis[maxn];
    int match[maxn];
    bool dfs(int u){
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(vis[v])continue;
            vis[v]=1;
            if(!match[v]||dfs(match[v])){//考场写的dfs(v)
                match[v]=u;return 1;
            }
        }
        return 0;
    }
    

    考虑墙对答案的影响,无非就是墙将本来属于一行的拆成了多行,将本来属于一列的拆成了多列。所以我们将行和列重新标号之后,就变成了裸的二分图放置问题。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=3000+10;
    int n,m,ans;
    char s[60][60];
    
    struct Edge{
        int from,to,nxt;
    }e[maxn<<1];
    
    int head[maxn],cnt;
    inline void add(int u,int v){
        e[++cnt].from=u;
        e[cnt].to=v;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    }
    
    inline int Get(int x,int y){
        return m*(x-1)+y;
    }
    
    int belrow[maxn],belcol[maxn];
    
    bool vis[maxn];
    int match[maxn];
    bool dfs(int u){
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(vis[v])continue;
            vis[v]=1;
            if(!match[v]||dfs(match[v])){
                match[v]=u;return 1;
            }
        }
        return 0;
    }
    
    int main(){
    #ifndef LOCAL
        freopen("robots.in","r",stdin);
        freopen("robots.out","w",stdout);
    #endif
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]+1);
        for(int i=1;i<=n;i++){
            belrow[0]++;
            for(int j=1;j<=m;j++){
                if(s[i][j]=='o'){
                    belrow[Get(i,j)]=belrow[0];
                }else if(s[i][j]=='#'&&j!=m&&s[i][j+1]!='#')belrow[0]++;
            }
        }
        for(int j=1;j<=m;j++){
            belcol[0]++;
            for(int i=1;i<=n;i++){
                if(s[i][j]=='o'){
                    belcol[Get(i,j)]=belcol[0];
                }else if(s[i][j]=='#'&&i!=n&&s[i+1][j]!='#')belcol[0]++;
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(s[i][j]=='o')add(belrow[Get(i,j)],belcol[Get(i,j)]);
        for(int i=1;i<=belrow[0];i++){
            memset(vis,0,sizeof(vis));
            if(dfs(i))ans++;
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    js 类型检测
    js笔记
    js 笔记 -- 随机生成颜色值
    js笔记 -- toString() 和String()
    jquery 实现的josnp
    json 、jsonp
    关于js 中的 this
    [LeetCode][JavaScript]Symmetric Tree
    [LeetCode][JavaScript]Balanced Binary Tree
    [LeetCode][JavaScript]Wiggle Sort II
  • 原文地址:https://www.cnblogs.com/Midoria7/p/13770040.html
Copyright © 2011-2022 走看看