第四届华中区程序设计邀请赛暨武汉大学第十三届校赛 网络预选赛

        武汉大学的校赛网络赛,之前WHUOJ上说网络赛晋级前20的外校队伍可以到武汉大学现场参加正式比赛,于是就参加了这场网络赛,结束的时候,由于罚时多了些,并没有进入前20,后来官网公布外校队伍名单,发现6题及以上的都晋级了,KILLBILL与Matrix在列,也是蛮surprise的~

        水题还是蛮多的,因为剩下的难题都没过...


B题:

10^6长的数字字符串,最多只有一次操作:选取区间[l,r],区间中所有元素xi变为(10-xi)%10 ,问数字字符串的最大元素和。

类似最大子串和的求法

以Sample Input 1为例:

   a  : 3   7  7  5  0  5  3   8  0   8

   b  : 7   3  3  5  0  5  7   2  0   2

增量: 4 -4 -4  0  0  0  4  -6  0  -6

dp   : 0  0  -4 0  0  0  4  -2   0  -6

Ans  = ∑{a} + max{dp}

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>

#define LL long long
#define inf 0x3f3f3f3f

using namespace std;

const int M = 1000100;
char str[M];

int a[M];
int dp[M];

int main() {
    int n;
    while(~scanf("%d",&n)) {
        scanf("%s",str);

        int len = strlen(str);

        int sum = 0;
        for(int i=0; i<len; i++) {
            a[i] = (10-(str[i]-'0'))%10 - (str[i]-'0');
            sum += (str[i]-'0');
        }

        dp[0] = max(a[0],0);
        for(int i=1; i<len; i++) {
            dp[i] = max(dp[i-1]+a[i],a[i]);
        }

        int maxn = 0;
        for(int i=0; i<len; i++) {
            maxn = max(maxn,dp[i]);
        }

        printf("%d\n",sum+maxn);
    }
    return 0;
}
/**
10
3775053808
10
2580294019
10
4701956095
10
8888822222
*/


C题:

N点M边的图,Q次操作:

Ai和Bi加一条权值为Wi的边,求出当前图的最小生成树.(N是10^3,M是10^5,Q是10^3)

将原图求一棵MST,然后Q次操作都对这棵生成树操作。

如果Ai和Bi之间原来有边,且Wi比原边权大,那么不需要更新边

如果Ai和Bi之间原来有边,且Wi比原边权小,那么更新边,生成树权值=原来生成树权值-原AiBi边权+Wi

如果Ai和Bi之间原来无边,加上边之后,一定会出现一个环,找出这个环上的最大边权,然后把这个边权删掉就变成了新的MST

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
class Tarjan_U {
    typedef int typec;
    static const int ME=20048;
    static const int MV=1024;
    struct Q {
        int u,v;
        typec w;
    } now;
    vector<Q> qiao;
    int Bcnt,Index,num[MV],dfn[MV],low[MV],belong[MV];
    stack<int> s;
    void addqiao(int u,int v,typec w) {
        now.u=u;
        now.v=v;
        now.w=w;
        qiao.push_back(now);
    }
    void tarjan(int u) {
        s.push(u);
        dfn[u]=low[u]=++Index;
        int v;
        for (int i=g.head[u]; ~i; i=g.e[i].next) {
            if(g.e[i].vis)continue;
            g.e[i].vis=g.e[i^1].vis=true;
            v=g.e[i].v;
            if (!dfn[v]) {
                tarjan(v);
                low[u]=min(low[u],low[v]);
                if(dfn[u]<low[v])
                    addqiao(u,v,g.e[i].w);
            } else low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]) {
            Bcnt++;
            do {
                v=s.top();
                s.pop();
                belong[v]=Bcnt;
                num[Bcnt]++;
            } while(v!=u);
        }
    }
public:
    struct G {
        struct E {
            int v,next;
            bool vis;
            typec w;
        } e[ME];
        int le,head[MV];
        void init() {
            le=0;
            mt(head,-1);
        }
        void add(int u,int v,typec w) {
            e[le].vis=false;
            e[le].v=v;
            e[le].w=w;
            e[le].next=head[u];
            head[u]=le++;
        }
    } g;
    void init() {
        g.init();
        Index=Bcnt=0;
        mt(num,0);
        mt(dfn,0);
        mt(low,0);
        qiao.clear();
        while(!s.empty()) s.pop();
    }
    void add(int u,int v,typec w) {
        g.add(u,v,w);
        g.add(v,u,w);
    }
    void solve(int n) {
        for(int i=1; i<=n; i++) {
            if(!dfn[i]) {
                tarjan(i);
            }
        }
    }
    int getbcnt() {
        return Bcnt;
    }
    int getbelong(int id) {
        return belong[id];
    }
    int getnum(int id) {
        return num[id];
    }
} T;

struct Edge {
    int u,v,w;
} edge[100010],now[2040];
int len;
class Kruskal {
    typedef int typec;
    static const int ME=100024;
    static const int MV=1024;
    class UnionFindSet { 
        int par[MV];
    public:
        void init() {
            mt(par,-1);
        }
        int getroot(int x) {
            int i=x,j=x,temp;
            while(par[i]>=0) i=par[i];
            while(j!=i) {
                temp=par[j];
                par[j]=i;
                j=temp;
            }
            return i;
        }
        bool unite(int x,int y) {
            int p=getroot(x);
            int q=getroot(y);
            if(p==q)return false;
            if(par[p]>par[q]) {
                par[q]+=par[p];
                par[p]=q;
            } else {
                par[p]+=par[q];
                par[q]=p;
            }
            return true;
        }
    } f;
    struct E {
        int u,v;
        typec w;
        friend bool operator < (E a,E b) {
            return a.w<b.w;
        }
    } e[ME];
    int le,num,n;
    typec res;
public:
    void init(int tn) {
        n=tn;
        le=res=0;
        f.init();
        num=1;
    }
    void add(int u,int v,int w) {
        e[le].u=u;
        e[le].v=v;
        e[le].w=w;
        le++;
    }
    typec solve() {
        sort(e,e+le);
        for(int i=0; i<le&&num<n; i++) {
            if(f.unite(e[i].u,e[i].v)) {
                num++;
                res+=e[i].w;
                now[len].u=e[i].u;
                now[len].v=e[i].v;
                now[len].w=e[i].w;
                len++;
            }
        }
        if(num<n) res=-1;
        return res;
    }
} gx;
const int M=1024;
bool vis[M];
int main() {
    int n,m,q,u,v,w;
    while(~scanf("%d%d%d",&n,&m,&q)) {
        for(int i=0; i<m; i++) {
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        }
        int ans=-1;
        while(q--) {
            scanf("%d%d%d",&u,&v,&w);
            if(ans==-1) {
                gx.init(n);
                for(int i=0; i<m; i++) {
                    gx.add(edge[i].u,edge[i].v,edge[i].w);
                }
                gx.add(u,v,w);
                len=0;
                ans=gx.solve();
                printf("%d\n",ans);
                continue;
            }
            if(u==v) {
                printf("%d\n",ans);
                continue;
            }
            int sid=-1;
            for(int i=0; i<n-1; i++) {
                if((u==now[i].u&&v==now[i].v)||(v==now[i].u&&u==now[i].v)) {
                    sid=i;
                    break;
                }
            }
            if(sid!=-1) {
                if(w<now[sid].w) {
                    ans=ans-now[sid].w+w;
                    now[sid].w=w;
                }
                printf("%d\n",ans);
                continue;
            }
            now[n-1].u=u;
            now[n-1].v=v;
            now[n-1].w=w;
            T.init();
            for(int i=0; i<n; i++) {
                T.add(now[i].u,now[i].v,now[i].w);
            }
            T.solve(n);
            int bcnt=T.getbcnt();
            int bid=1;
            for(int i=1; i<=bcnt; i++) {
                if(T.getnum(i)>1) {
                    bid=i;
                    break;
                }
            }
            for(int i=1; i<=n; i++) {
                vis[i]=false;
            }
            for(int i=1; i<=n; i++) {
                if(T.getbelong(i)==bid) {
                    vis[i]=true;
                }
            }
            int big=0;
            int tou,tov;
            for(int i=0; i<n; i++) {
                if(vis[now[i].u]&&vis[now[i].v]) {
                    if(big<now[i].w) {
                        big=now[i].w;
                        tou=now[i].u;
                        tov=now[i].v;
                    }
                }
            }
            ans=0;
            int id=0;
            for(int i=0; i<n; i++) {
                u=now[i].u;
                v=now[i].v;
                w=now[i].w;
                if((u==tou&&v==tov)||(v==tou&&u==tov)) {
                    id=i;
                    continue;
                }
                ans+=w;
            }
            swap(now[id],now[n-1]);
            printf("%d\n",ans);
        }
    }
    return 0;
}
/**3 3 3
1 2 3
1 2 4
2 3 5
1 2 4

2 3 4
*/


D题:

用最少的矩阵把这玩意儿围起来


贪心方法,先扫一遍两个0中间的区间中的最大值,然后用矩阵来围起来,每一个元素减去这个最大值,然后重复上述步骤直到所有的元素都减成0

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

#define mt(a,b) memset(a,b,sizeof(a))
#define LL long long

using namespace std;
const int inf = 0x3f3f3f3f;
int n;
int a[1234];

int main(){
    while(~scanf("%d",&n)){
        a[0] = 0;
        a[n+1] = 0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }

        bool flag = true;
        int ans = 0;
        while(flag){
            flag = false;
            int s = -1;
            int e = -1;
            for(int i=0;i<=n;i++){
                if(a[i]!=0 && a[i-1]==0 && s==-1){
                    s = i;
                }
                if(a[i]!=0 && a[i+1]==0 && s!=-1){
                    e = i;
//                    printf("--->%d  %d\n",s,e);
                    int minn = inf;
                    for(int j=s;j<=e;j++){
                        minn = min(minn,a[j]);
                    }
                    ans ++;
                    flag = true;
                    for(int j=s;j<=e;j++){
                        a[j] -= minn;
                    }
                    i=e;
                    s = -1;
                    e = -1;
                }
            }
        }

        printf("%d\n",ans);

    }
    return 0;
}


F题:

长度为20的数字,选一个位置,截为前后两段,使得前后差值最小(绝对值)

如果单纯的认为从中间截断是错误的,因为对于140000,最好的方案是14-0000,而不是140-000

枚举截断的位置,然后高精度进行运算

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>

#define LL long long
#define inf 0x3f3f3f3f
#define mt(a,b) memset(a,b,sizeof(a))

using namespace std;

const int M = 50;
char str[M];

class Hp { //高精度类
    int len,s[M];
public:
    void init() {
        len=1;
        mt(s,0);
    }
    void init(char ch[]) {
        len=1;
        mt(s,0);
        int i=0;
        while(ch[i]=='0'&&ch[i]!=0) i++;
        if(ch[i]!=0) {
            len=strlen(ch)-i;
            int pre = 0;
            for(int j=strlen(ch)-1; j>=i; j--) {
                s[pre]=ch[j]-48;
                pre++;
            }
        }
    }
    void init(int x) {
        len=1;
        mt(s,0);
        while(x) {
            s[len-1]=x%10;
            x/=10;
            if(x) len++;
        }
    }
    void init(const Hp& a) {
        len=a.len;
        for(int i=0; i<M; i++) {
            s[i]=a.s[i];
        }
    }
    void print() { //输出
        int i=len-1;
        while(s[i]==0&&i>0) i--;
        for(; i>=0; i--) {
            printf("%d",s[i]);
        }
    }
    int cmp(Hp a) { //比较,类似于char数组比较
        if(len<a.len) return -1;
        else if(len>a.len) return 1;
        else {
            int temp=len-1;
            while(temp>=0&&s[temp]==a.s[temp]) temp--;
            if(temp==-1) return 0;
            else if(s[temp]<a.s[temp]) return -1;
            else return 1;
        }
    }


    void subtract(Hp a) { //高精度减高精度
        for(int i=0; i<len; i++) {
            s[i]-=a.s[i];
            if(s[i]<0) {
                s[i]+=10;
                s[i+1]--;
            }
        }
        while(len>1&&s[len-1]==0) len--;
    }

};

int main() {
    Hp A,B,Cha;
    char a[25],b[25];
    int n;
    while(~scanf("%s",str)) {
        Hp Ans;
        Ans.init(str);
        int len = strlen(str);
        for(int i=0; i<len-1; i++) {
            mt(a,0);
            mt(b,0);
            for(int j=0; j<=i; j++) {
                a[j] = str[j];
            }
            int pre = 0;
            for(int j=i+1; j<len; j++) {
                b[pre] = str[j];
                pre++;
            }


            A.init(a);
            B.init(b);
//            puts("**************************");
            puts(a);
            puts(b);
//            A.print();
//            puts("");
//            B.print();
//            puts("");
//            puts("**************************");

            ///A<B
            if(A.cmp(B)==-1) {
                B.subtract(A);
//                B.print();
//                puts("***");

                if(B.cmp(Ans)==-1) {
                    Ans.init(B);
                }
            } else {
                A.subtract(B);
//                A.print();
//                puts("****");
//                A.print();
//                puts("");
//                B.print();
//                puts("");
                if(A.cmp(Ans)==-1) {
                    Ans.init(A);
                }
            }

        }

        Ans.print();
        puts("");

    }
    return 0;
}
/**
457
75462
734794666
12345678900987654321
*/

///113580246


G题:

N个数选M个,是的方差最小。1 <= M <= N <= 30

要是方差最小,那么数越连续越好

将N个数排个序

O(N)遍历,每次拿连续的M个,更新方差最小值

PS:一开始考虑到精度问题,后来尝试交了一发,把数据水过去了

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef  double lb;
int a[64];
lb b[64];
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        sort(a,a+n);
        for(int i=0;i<n;i++){
            b[i]=a[i];
        }
        lb ans=1e22;
        for(int i=0;i<n;i++){
            if(i+m>n) break;
            lb sum=0;
            for(int j=i;j<i+m;j++){
                sum+=b[j];
            }
            lb avg=sum/m;
            lb s=0;
            for(int j=i;j<i+m;j++){
                s+=(b[j]-avg)/m*(b[j]-avg);
            }
            ans=min(ans,s);
        }
        printf("%.3f\n",ans);
    }
    return 0;
}


H题:

又是我最最讨厌的小学追击类问题,类似于校赛上的“鹊桥相会”

上小学的Alice,在平时,她的拔拔Fzz会在正好在放学时开车到达学校,然后接上Alice就回家

有一天学校提前放学了,Alice发现比平时早了x分钟,然后Alice就开始步行回家,走了y分钟后,遇到了Fzz,然后上车回家,到家后发现比以往到家早了z分钟

现在给出x,y,z的任意两个值,求出剩下的一个值

设平时放学时间为t0,平时到家时间为t1,Alice速度为v,Fzz开车速度为V

(1)根据学校到家的距离,有vy+(t1-z-t0+x-y)V=(t1-t0)V

     ---> v/V = (z-x+y)/y

(2)考虑到节省的z时间,其实节省的是Fzz从Alice遇到Fzz位置到学校距离的开车来回一趟时间,有2vy=Vz

     ---> v/V = z/2y

∴(z-x+y)/y = z/2y  ---> z/2 = x-y

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

#define mt(a,b) memset(a,b,sizeof(a))
#define LL long long

using namespace std;
const int inf = 0x3f3f3f3f;

int cal(char str[]){
    int len = strlen(str);
    int res = 0;
    for(int i=0;i<len;i++){
        res = res*10+(str[i]-'0');
    }
    return res;
}

int main(){
    int _;
    char str[20];
    while(~scanf("%d",&_)){
        while(_--){
        int x = -1;
        int y = -1;
        int z = -1;
            scanf("%s",str);
            if(str[0] != '?'){
                x = cal(str);
            }
            scanf("%s",str);
            if(str[0] != '?'){
                y = cal(str);
            }
            scanf("%s",str);
            if(str[0] != '?'){
                z = cal(str);
            }

//            printf("--->%d %d %d\n",x,y,z);

            if(x==-1){
                printf("%d\n",z/2+y);
                continue;
            }

            if(y==-1){
                printf("%d\n",x-z/2);
                continue;
            }

            if(z==-1){
                printf("%d\n",(x-y)*2);
            }


        }
    }

    return 0;
}
/**
3
? 30 20
40 ? 20
40 30 ?
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值