• 2020 年 “联想杯”全国高校程序设计在线邀请赛


    左手太顶了,369太9了,水子哥又成白开水了!!!

    传过去送的门

    感觉还是难题做不了,水题做不快,都不知道怎么提升了。但先走下去吧,等一波奇迹团。

    这次才做了7个,太菜了(还是在我360秘书的帮助下),剩下的看能力补。。。

    B.Bamboo Leaf Rhapsody 

    题意大概就是给你n个三维的点,找离(0,0,0)最近的点的距离。for一遍。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int main(){
        int n;
        double ans=1e9+11;
        scanf("%d",&n);
        while(n--){
            double x,y,z;
            scanf("%lf%lf%lf",&x,&y,&z);
            ans=min(ans,sqrt(x*x+y*y+z*z));
        }
        printf("%.3f
    ",ans);
        return 0;
    } 
    签个到

    A.Archmage

    一开始有n>=x+y个mana,然后每秒会增加y个mana,并且每秒可以花费x个mana换1个Water Element,换操作是在增加操作之前的。问m秒后最多能有几个Water Element?

    当x<=y,一直有mana课进行交换,x<y时,m-1秒增加的mana都有可能用上。

    在m跟(n+(m-1)*y)/x取个最小值就好。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            ll n,m,x,y;
            scanf("%lld%lld%lld%lld",&n,&m,&x,&y);
            printf("%lld
    ",min(m,(n+(m-1)*y)/x));
        }
        return 0;
    } 
    x换1,这波大亏

    C.Cheat Sheet

    有m个可能重复的单词,笔记本最多记n个字符,每两个单词之间用一个空格隔开(会占用一个字符的位置),问最多记几个不一样的单词。

    将单词按照长度,再按字典序排序,然后模拟即可。

    这里发现个坑爹的地方,n=-1的时候,-1>=s[i].size()居然是true,不知道是为什么,希望有道友指点一下。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    string s[1011];
    bool cmp(string a,string b){
        return a.size()==b.size() ? a<b : a.size()<b.size();
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++) cin>>s[i];
        sort(s,s+m,cmp);
        int ans=0;
        for(int i=0;i<m;i++){
            if(i&&s[i]==s[i-1]) continue;
            if(n>=s[i].size()){
                ans++;
                n-=s[i].size();
            }else break;
            n--;
            if(n<=0) break;
        }
        printf("%d
    ",ans);
        return 0;
    }
    不,我不想记单词

    H.Hay Mower 

    (这表情包我喜欢艹艹艹艹艹艹)

     有n*m的草地,每个位置每秒会长aij的草,而在第t秒时,这个小熊会割掉一整行,或者一整列的草。问割了k次草后,小熊一共割了多少草。

    一开始的想法复杂,但觉得可行也就直接敲了,没有往更简单的地方想。

    我第一想法就是,时间从后往前,每一行每一列只会被割一次,那标记一下这一行和这一列有没有被割过就好。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=511,M=3e5+11;
    const ll md=998244353;
    char op[M][5];
    bool visx[N],visy[N];
    int pos[M];
    ll a[N][N],xsum[N],ysum[N],tt[M];
    int main(){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                scanf("%lld",&a[i][j]);
                a[i][j]%=md;
                xsum[i]+=a[i][j];
                if(xsum[i]>=md) xsum[i]-=md;
                ysum[j]+=a[i][j];
                if(ysum[j]>=md) ysum[j]-=md;
            }
        for(int i=0;i<k;i++) scanf("%s%d%lld",op[i],&pos[i],&tt[i]);
        ll ans=0;
        for(int i=k-1;i>=0;i--){
            tt[i]%=md;
            if(op[i][0]=='r'){
                if(visx[pos[i]]) continue;
                visx[pos[i]]=true;
                ans+=xsum[pos[i]]*tt[i]%md;
                xsum[pos[i]]=0;
                if(ans>=md) ans-=md;
                for(int j=1;j<=m;j++){
                    if(visy[j]) continue;
                    ysum[j]-=a[pos[i]][j];
                    if(ysum[j]<0) ysum[j]=(ysum[j]%md+md)%md;
                    if(ysum[j]==0) visy[j]=true;
                }
            }else{
                if(visy[pos[i]]) continue;
                visy[pos[i]]=true;
                ans+=ysum[pos[i]]*tt[i]%md;
                ysum[pos[i]]=0;
                if(ans>=md) ans-=md;
                for(int j=1;j<=n;j++){
                    if(visx[j]) continue;
                    xsum[j]-=a[j][pos[i]];
                    if(xsum[j]<0) xsum[j]=(xsum[j]%md+md)%md;
                    if(xsum[j]==0) visx[j]=true;
                }
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    复杂的艹

    但由行列就可想到,某个位置,假如3秒被割了一次,5秒又被割了一次,那么直接视为5秒时割的就好。

    有个坑就是,不能先对时间取模,先比了大小先再取模。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=511;
    const ll md=998244353;
    ll a[N][N],r[N],c[N];
    int main(){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                scanf("%lld",&a[i][j]);
                a[i][j]%=md;
            }
        char op[3];
        int pos;
        ll tt; 
        for(int i=0;i<k;i++){
            scanf("%s%d%lld",op,&pos,&tt);
            if(op[0]=='r') r[pos]=tt;
            else c[pos]=tt;
        }
        ll ans=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                ans=(ans+max(r[i],c[j])%md*a[i][j]%md)%md;
            }
        printf("%lld
    ",ans);
        return 0;
    }
    简单的艹

    D.Disaster Recovery

    有1~n个点第i个点的权值就是斐波那契数第i项,m条边,每条的边权是两个点权和,问最小生成树中点的最大度数。

    一开始也想复杂了,还想着二分找度数,但在判断它是不是最小生成树的时候就突然醒悟。

    假设有a-b,c-d这两条边其中a<b,c<d,那么fib[a]+fib[b]!=fib[c]+fib[d],也就是任意两条边的边权不会相同。

    因为假设b>=d+1,那么fib[b]>=fib[d]+fib[d-1],而c<=d-1,所以fib[a]+fib[b]>fib[c]+fib[d].

    任意两条边的边权不会相同,那么最小生成树就只有一棵,直接求就行了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+11;
    struct Side{
        int u,v;
        bool operator<(Side &s1)const{
            return v==s1.v ? u<s1.u : v<s1.v;
        }
    }S[N*2];
    int n,m,fa[N],du[N];
    int find(int x){
        return fa[x]==x ? x : fa[x]=find(fa[x]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
            scanf("%d%d",&S[i].u,&S[i].v);
            if(S[i].u>S[i].v) swap(S[i].u,S[i].v);
        }
        sort(S,S+m);
        for(int i=1;i<=n;i++) fa[i]=i,du[i]=0;
        int cnt=0,ans=0;
        for(int i=0;i<m;i++){
            int u=S[i].u,v=S[i].v;
            int fu=find(u),fv=find(v);
            if(fu==fv) continue;
            cnt++;
            fa[fu]=fv;
            du[u]++;du[v]++;
            ans=max(ans,max(du[u],du[v]));
            if(cnt==n-1) break;
        }
        printf("%d
    ",ans);
        return 0;
    }
    绿的草绿的树

    L.Lottery Tickets

    0~9每个数有c[i]个,问用这些数能组成的最大的4的倍数是什么。

    一开始没啥思路,刚想换题,突然想起来4的倍数好像有个规律,然后就打表看了一下。

    果不其然,4的倍数的规律就是2位数及以上的数最后两个数都是在某25个数之间循环的。

    所以把这25个可能的最后2位数打出来,然后按照两个数的大小进行排序,让数小的在前面,然后枚举即可。

    #include<bits/stdc++.h>
    using namespace std;
    int a[31]={
    0,20,12,32,40,
    24,44,52,60,16,
    36,64,56,72,76,
    80,28,84,48,68,
    88,92,96,};
    int c[11],nd[11];
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            for(int i=0;i<=9;i++) scanf("%d",&c[i]);
            int flag=0;
            for(int i=0;i<23&&!flag;i++){
                int x=a[i]/10,y=a[i]%10;
                nd[x]++;nd[y]++;
                if(c[x]>=nd[x]&&c[y]>=nd[y]){
                    flag=1;
                    c[x]--;c[y]--;
                    int pre0=1;
                    for(int j=9;j>=0;j--){
                        if(c[j]){
                            if(j) pre0=0;
                            if(!j&&pre0) continue;
                            for(int k=0;k<c[j];k++) printf("%d",j);
                        }
                    }
                    if(x||!pre0) printf("%d",x);
                    printf("%d
    ",y);
                }
                nd[x]--;nd[y]--;
            }
            if(!flag){
                if(c[8]) printf("8
    ");
                else if(c[4]) printf("4
    ");
                else if(c[0]) printf("0
    ");
                else printf("-1
    ");
            }
        }
        return 0;
    }
    0 4 8 12 16...

    做了L就去吃东西了,看了一会比赛。。。然后回来傻逼的开了M,搞了快1个小时都没得。

    最后看G过的多,去看了一眼,再让我360秘书帮忙翻译了一下。然后发现,啊,这波,这波是个水题。

    G.Gentle Jena

    题意里定义了一下函数,我就不说题意了。。。

    设a[i]为以i为右边界的区间的答案,也就是题目中的A[i]=a[1]+a[2]+...+a[i]

    每增加一个数bi+1,增加的区间就是[1,i+1],[2,i+1]...[i+1,i+1],

    那么假设pos为bi+1左边第一个小于等于它的数的位置,那么bi+1作为最小值的区间也就是[pos+1,i+1],[pos+1,i+1]...[i+1,i+1]

    而剩下的[1,i+1],[2,i+1]...[pos,i+1]由于bpos<bi+1,所以完全可以看出区间[1,pos],[2,pos]...[pos,pos]

    也就是a[i]=b[i]*(i-pos)+a[pos],pos为i左边第一个小于等于b[i]的数的位置,可用单调栈求得。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e7+11;
    const ll md=998244353;
    stack<int> sta;
    ll a[N],b[N],ans[N];
    int main(){
        int n;
        ll p,x,y,z;
        scanf("%d%lld%lld%lld%lld%lld",&n,&p,&x,&y,&z,&b[1]);
        ans[1]=a[1]=b[1];
        b[0]=-1;
        sta.push(0);
        sta.push(1);
        for(int i=2;i<=n;i++){
            b[i]=(x*ans[i-1]%p+y*b[i-1]%p+z)%p;
            while(!sta.empty()&&b[sta.top()]>b[i]) sta.pop();
            int pos=sta.top();
            a[i]=(b[i]*(i-pos)%md+a[pos])%md;
            ans[i]=(ans[i-1]+a[i])%md;
            sta.push(i);
        }
        ll res=0;
        for(int i=1;i<=n;i++) res^=ans[i];
        printf("%lld
    ",res);
        return 0;
    }
    右边的区间看过来
  • 相关阅读:
    JAVA不可变类(immutable)机制与String的不可变性
    如何高效学习
    [细品java]ThreadLocal源码学习
    Spring 入门知识点笔记整理
    spring远程服务知识梳理
    Spring Security 入门详解
    Selenium 安装 geckdriver Firefox 对应关系 历史版本下载
    Redhat linux 下 Jmeter 非GUI界面执行压力测试
    Spring Boot 进程守护 修改启动端口号 Spring Boot 监听端口被占用无法启动
    Redhat Linux 部署maven环境
  • 原文地址:https://www.cnblogs.com/LMCC1108/p/12995400.html
Copyright © 2020-2023  润新知