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;
    }
    
  • 相关阅读:
    CF1454F Array Partition
    leetcode1883 准时抵达会议现场的最小跳过休息次数
    leetcode1871 跳跃游戏 VII
    leetcode1872 石子游戏VIII
    CF1355C Count Triangles
    CF1245D Shichikuji and Power Grid
    CF1368C Even Picture
    CF1368D AND, OR and square sum
    CF1395C Boboniu and Bit Operations
    SpringBoot和开发热部署
  • 原文地址:https://www.cnblogs.com/Midoria7/p/13770040.html
Copyright © 2011-2022 走看看