ICode9

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

联合省选2021A卷 补题记录

2021-04-13 14:35:37  阅读:146  来源: 互联网

标签:ch const 省选 ll -- 补题 2021A il define


本来是不打算订正的,但今天没题,也比较无聊。


D1T1 Card

心态从这里开始炸的,口胡的结论不加以证明,也没举反例就随便写是我的老毛病了,现在也算是吃到了恶果。
正解应该是枚举 最小(或最大值),再去二分(或者用双指针)去找到另一头的最值,记录一下最小的极差。
刚进考场第一眼写的就是这个,可惜排序顺序假了,我并没有按照 \(a\) 和 \(b\) 的最小值排序,只按了 \(a\) 排序,调了一个小时也没有过样例,直接放弃了这种写法。
转而开始口胡结论:答案关于最小/最大值是一个凸函数。随便举几个例子都能hack这个结论,但是场上犯病了,没去多想,觉得很有道理就直接去码了,再加上巨水无比的样例...

用了基排,总复杂度是 \(O(n)\) 的。

Code

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define ll long long
#define ui unsigned int
il ll read(){
    bool f=true;ll x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=false;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    if(f) return x;
    return ~(--x);
}
il void write(const ll &x){if(x>9) write(x/10);putchar(x%10+'0');}
il void print(const ll &x) {x<0?putchar('-'),write(~(x-1)):write(x);putchar('\n');}
il ll max(const ll &a,const ll &b){return a>b?a:b;}
il ll min(const ll &a,const ll &b){return a<b?a:b;}
ll n,m,ans;
const int MAXN=2e6+7;
struct node
{
    int v,id,w;
}a[MAXN];
int del[MAXN];
namespace Sort{
    int cnt1[256],cnt2[256],cnt3[256],cnt4[256];
    node temp[MAXN];
    void mysort(node a[],int l,int r){
        ri i;
        node *p;
        for (i=l,p=a+l;i <= r;++ i,++p){
            ++ cnt1[p->v & 255];
            ++ cnt2[p->v >> 8 & 255];
            ++ cnt3[p->v >> 16 & 255];
            ++ cnt4[p->v >> 24 & 255];
        }
        for (i = 1;i <= 255;++ i){
            cnt1[i] += cnt1[i - 1];
            cnt2[i] += cnt2[i - 1];
            cnt3[i] += cnt3[i - 1];
            cnt4[i] += cnt4[i - 1];
        }
        for (i = r,p=&a[r];i >= l;-- i,--p) temp[cnt1[p->v & 255] --] = *p;
        for (i = r,p=&temp[r];i >= l;-- i,--p) a[cnt2[p->v >> 8 & 255] --] = *p;
        for (i = r,p=&a[r];i >= l;-- i,--p) temp[cnt3[p->v >> 16 & 255] --] = *p;
        for (i = r,p=&temp[r];i >= l;-- i,--p) a[cnt4[p->v >> 24 & 255] --] = *p;
    }
}
int main(){
    // freopen("card/card3.in","r",stdin);
    // freopen("card/card3.out","w",stdout);
    n=read(),m=read();
    for(ri i=1;i<=n;++i) a[i].v=read(),a[i].id=i,a[i].w=1;
    for(ri i=1;i<=n;++i) a[n+i].v=read(),a[n+i].id=i;
    Sort::mysort(a,1,n<<1);
    ll l=0,r=2*n+1,use=0;
    while(!del[a[l+1].id]&&use+a[l+1].w<=m){
        l++;
        del[a[l].id]=1;
        use+=a[l].w;
    }
    while(!del[a[r-1].id]&&use+a[r-1].w<=m){
        r--;
        del[a[r].id]=1;
        use+=a[r].w;
    }
    ans=1e18;
    while(~l){
        ans=min(a[r-1].v-a[l+1].v,ans);
        use-=a[l].w;
        del[a[l].id]=0;
        while(!del[a[r-1].id]&&use+a[r-1].w<=m){
            r--;
            del[a[r].id]=1;
            use+=a[r].w;
        }
        l--;
    }
    print(ans);

    return 0;
}

D1T2 Matrix

考场上一眼看出来是差分约束,但是没建出来模型,也忘了怎么敲差分约束,甚至连 \(m=2\) 的点都写挂了构造题不发checker是真的牛批
首先,先考虑如果没有 \([0,10^6]\) 的限制,可以直接钦定第一行和第一列(一般来说钦定为多少都可以)。
然后可以发现已经可以把整个矩形给推出来了。
然后有这样一个性质,对于某一行来说,将这一行中的元素 \(+1,-1,+1,-1 \dots\) 这样交替加减是不会影响 \(b\) 数组的。
于是,设数组 \(r_j\) 表示在第 \(j\) 列的操作数,\(c_i\) 表示在第 \(i\) 行的操作数。
大概可以列出来这样一个矩阵:

\[\left[ \begin{matrix} 0&r_1&-r_2&r_3&\dots&-r_m\\ -c_1& r_1-(-c_1)\in[-a_{1,1},1e6-a_{1,1}] &-c_1-(-r_2)\in[-a_{2,1},1e6-a_{2,1}]&\dots\\ c_2& c_2-r_1\in[-a_{1,2},1e6-a_{1,2}] &\dots\\ -c_3&\vdots&\ddots\\ \vdots\\ c_n\\ \end{matrix} \right] \]

分奇偶讨论跑差分约束 SPFA会被卡,建议先判个负环再跑dij

Code

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define ll long long
#define ui unsigned int
il ll read(){
    bool f=true;ll x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=false;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    if(f) return x;
    return ~(--x);
}
il void write(const ll &x){if(x>9) write(x/10);putchar(x%10+'0');}
il void print(const ll &x) {x<0?putchar('-'),write(~(x-1)):write(x);putchar('\n');}
il ll max(const ll &a,const ll &b){return a>b?a:b;}
il ll min(const ll &a,const ll &b){return a<b?a:b;}
const int MAXN=305+7;
ll a[MAXN][MAXN],b[MAXN][MAXN],n,m;
ll vis[MAXN<<1],dis[MAXN<<1],in[MAXN<<1];
il int id(int x,int y){return x*(m-1)+y;}
struct edge
{
    ll u,w;
};

vector<edge> g[MAXN<<1];
bool SPFA(){
    queue<int> q;
    for(ri i=1;i<=n+m;++i) vis[i]=dis[i]=0,q.push(i),in[i]=1;
    while(!q.empty()){
        int s=q.front();q.pop();
        in[s]=0;
        for(ri i=0;i<g[s].size();++i){
            edge now=g[s][i];
            if(dis[s]+now.w<dis[now.u]){
                dis[now.u]=dis[s]+now.w;
                if(!in[s]){
                    q.push(now.u);
                    if(++vis[now.u]>n+m){
                        return 0;
                    }
                    in[now.u]=1;
                }
            }
        }
    }
    return 1;
}
int main(){
    for(ri t=read();t;--t){
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        n=read(),m=read();
        for(ri i=1;i<=n+m;++i) g[i].clear(),vis[i]=dis[i]=0;
        for(ri i=1;i<n;++i)
        for(ri j=1;j<m;++j)
        b[i][j]=read();
        for(ri i=1;i<n;++i){
            for(ri j=1;j<m;++j){
                a[i+1][j+1]=b[i][j]-a[i][j]-a[i][j+1]-a[i+1][j];
            }
        }
        for(ri i=1;i<=n;++i){
            for(ri j=1;j<=m;++j){
                int l,r;
                if((i+j)&1) r=j,l=m+i;
                else r=m+i,l=j;
                g[l].push_back((edge){r,a[i][j]});
                g[r].push_back((edge){l,-a[i][j]+(ll)1e6});
            }
        }
        if(SPFA()){
            puts("YES");
            for(ri i=1;i<=n;++i){
                for(ri j=1;j<=m;++j){
                    if((i+j)&1) a[i][j]-=dis[j]-dis[m+i];
                    else a[i][j]+=dis[j]-dis[m+i];

                    // if(j&1) a[i][j]-=dis[m+i];
                    // else a[i][j]+=dis[m+i];
                    printf("%lld ",a[i][j]);
                }
                puts("");
            }
        }
        else puts("NO");
    }
    return 0;
}

D1T3 graph

开这题的时候已经只剩下半个多小时了,只敲了个暴力上去,顺便得到了一个性质:
如果能从 \(v\) 能对 \(u\) 造成贡献,那么途中不能有比 \(v\) 小的点。
这个性质应该挺显然的,如果途中有比 \(v\) 小的点,那么它一定在之前已经被删除了。
实际上,有了这个性质之后,已经可以得到一个 \(O(n^3+m)\) 的做法了 %zjjws
把删边改成从 \(m~1\) 依次加边,记录从 \(u\) 到 \(v\) 的路径最早是在什么时候出现的,这个可以用 \(Floyd\) \(O(n^3)\)实现,然后做一个差分。
所以总复杂度 \(O(n^3+m)\)。
看上去似乎无法通过,实际上这个 \(Floyd\) 的常数是 \(\frac{1}{2}\) ,并且只有 \(\min \max\) 两种操作,手写函数之后加一点寻址优化还是能比较轻松的卡过去的指1s的时限要跑994ms

Code

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define ll long long
#define ui unsigned int
il ll read(){
    bool f=true;ll x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=false;ch=getchar();}
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    if(f) return x;
    return ~(--x);
}
il void write(const ll &x){if(x>9) write(x/10);putchar(x%10+'0');}
il void print(const ll &x) {x<0?putchar('-'),write(~(x-1)):write(x);putchar('\n');}
il ll max(const ll &a,const ll &b){return a>b?a:b;}
il ll min(const ll &a,const ll &b){return a<b?a:b;}
const int MAXN=1e3+7;
int f[MAXN][MAXN];
ll ans;
int n,m;
const int MAXM=2e5+7;
ll h[MAXM];
int main(){
    //freopen("2.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read(),m=read();
    memset(f,0x3f,sizeof(f));
    for(ri i=1;i<=n;++i) f[i][i]=0;
    for(ri i=1;i<=m;++i){
        int u=read(),v=read();
        f[u][v]=m-i+1;
    }
    for(ri i=n;i;--i){
        for(ri j=1;j<=n;++j){
            if(f[j][i]>m) continue;
            if(j<i){ 
                if(j&1){
                    for(ri k=1;k<=n;++k)
                    f[j][k]=min(f[j][k],max(f[j][i],f[i][k]));
                }
                else{
                    for(ri k=n;k;--k)
                    f[j][k]=min(f[j][k],max(f[j][i],f[i][k]));
                }
            }
            else if(j>i){
                if(j&1){
                    for(ri k=1;k<i;++k)
                    f[j][k]=min(f[j][k],max(f[j][i],f[i][k]));
                }
                else{
                    for(ri k=i-1;k;--k)
                    f[j][k]=min(f[j][k],max(f[j][i],f[i][k]));
                }
            }
        }
    }
    for(ri i=1;i<=n;++i){
        for(ri j=1;j<=i;++j){
            if(f[i][j]<=m&&f[j][i]<=m) h[max(f[i][j],f[j][i])]++; 
        }
    }
    for(ri i=1;i<=m;++i) h[i]+=h[i-1];
    for(ri i=m;~i;--i) write(h[i]),putchar(' ');
    return 0;
}

标签:ch,const,省选,ll,--,补题,2021A,il,define
来源: https://www.cnblogs.com/Guts/p/14653041.html

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

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

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

ICode9版权所有