zoukankan      html  css  js  c++  java
  • 19icpc网络赛补题记录及题解

    1. 南京网络赛
      A
      题意:一个蛇形矩阵,每个数美丽值等于十进制各位的权值相加,标记一些点,每次问一个矩阵内美丽值之和在这里插入图片描述
      思路:可以通过根据x,y推出被标记的点数值,再利用二维偏序按x排序,树状数组维护y。每次查询为二维平面的矩阵差分。
      代码:
    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(ll i=0;i<n;i++)
    #define for1(i,n) for(ll i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const ll maxn = 2e6+5;
    const ll maxm = 1e6+5;
    ll n,m,mm;
    ll ans[maxm];
    struct Q{
        ll x,y,id,flag,v;
    }q[maxm<<1];
    bool cmp(Q a,Q b){
        if(a.x==b.x) {
            if(a.y==b.y) return a.id<b.id;
            return a.y<b.y;
        }
        return a.x<b.x;
    }
    struct BIT{
        ll node[maxn];
        ll lb(ll x){return x&(-x);}
        void init(){forn(i,maxn)node[i] = 0;}
        void update(ll pos,ll v){for(ll i = pos;i<=n;i+=lb(i))node[i]+=v;}
        ll ask(ll pos){ll sum = 0;for(ll i = pos;i;i-=lb(i))sum+=node[i];return sum;}
        ll query(ll l,ll r){return ask(r)-ask(l-1);}
    }bit;
    ll func(ll x,ll y)
    {
        x=n+1-x;
        y=n+1-y;
        ll ans;
        ll mi=min(x,min(y,min(n-x+1,n-y+1)));
        if(x<=y) ans=1ll*mi*(1ll*4*(n-1)-4*mi)+1ll*10*mi-4*n-3+x+y;
        else ans=1ll*mi*(4*n-4*mi)+1ll*2*mi+1-x-y;//模拟过程
        ll tot=0;
        while (ans)
        {
            tot+=ans%10;
            ans/=10;
        }
        return tot;
    }
    void init(){
        bit.init();
        forn(i,maxm) ans[i] = 0;
        forn(i,maxm<<1) q[i] = {0,0,0,0,0};
    }
    int main(){
        IO;
        ll t;cin>>t;
        while(t--){
            cin>>n>>m>>mm;
            init();
            ll cnt = 0;
            forn(i,m){
                ll x,y;cin>>x>>y;
                ll z = func(x,y);
                q[cnt++] = {x,y,0,0,z};//x,y,id,flag,v
            }
            forn(i,mm){
                ll x,y,xx,yy;cin>>x>>y>>xx>>yy;
                q[cnt++] = {xx,yy,i,1,0};
                if(x>1&&y>1) q[cnt++] = {x-1,y-1,i,1,0};
                if(x>1) q[cnt++] = {x-1,yy,i,-1,0};
                if(y>1) q[cnt++] = {xx,y-1,i,-1,0};
            }
            sort(q,q+cnt,cmp);
            forn(i,cnt){
                if(q[i].flag==0) bit.update(q[i].y,q[i].v);
                else ans[q[i].id] += bit.ask(q[i].y)*q[i].flag;            
            }
            forn(i,mm) cout<<ans[i]<<'
    ';
        }
        return 0;
    }
    

    H
    题意:有向图,有负权值边,新添加给定两点的边,使得图中没有负环,且添加边权尽可能小。
    思路:spfa
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int inf = 0x3f3f3f3f;
    const int maxn = 305;
    int d[maxn],vis[maxn];
    vector<pair<int,int> >e[maxn];
    
    void init(){
        forn(i,maxn) e[i].clear();
    }
    
    int spfa(int s,int t){
        forn(i,maxn) vis[i] = 0,d[i] = inf;
        queue<int>q;
        q.push(t);d[t] = 0;
        while(!q.empty()){
            int u = q.front();q.pop();
            vis[u] = 0;
            for(auto x:e[u]){
                int v = x.first,w = x.second;
                if(d[v]>d[u]+w){
                    d[v] = d[u]+w;
                    if(!vis[v]){
                        q.push(v);
                        vis[v] = 1;
                    }
                }
            }
        }
        e[s].push_back({t,-d[s]});
        return -d[s];
    }
    
    int main(){
        IO;
        int t;cin>>t;
        while(t--){
            init();
            int n,m;cin>>n>>m;
            forn(i,m){
                int u,v,w;cin>>u>>v>>w;
                e[u].push_back({v,w});
            }
            forn(i,6){
                int s,t;cin>>s>>t;
                cout<<spfa(s,t)<<'
    ';
            }
        }
        return 0;
    }
    
    1. 徐州
      B
      题意:1e9个点,1e5次操作,a:可让一个点永久失效,b:查询一个点往后最近的有效点。
      思路:并查集,unorderd_map
      代码:
    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(itn i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    
    unordered_map<int,int> mp;
    
    int find(int x){
        return mp.count(x)?mp[x] = find(mp[x]):x;
    }
    
    int main(){ 
        IO;
        int n,q;cin>>n>>q;
        while(q--){
            int op,x;cin>>op>>x;
            if(op==1) mp[x] = x+1;
            else cout<<find(x)<<'
    ';
        }
        return 0;
    }
    

    D.
    模拟kmp板子
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int maxn = 1e5+5;
    
    int nex[maxn],nex2[maxn];
    
    void getnex(string &s){
        int len = s.size(),i = 0,j = -1;
        nex[0] = -1;
        while(i<len){
            if(s[i]==s[j]||j==-1) nex[++i] = ++j;
            else j = nex[j];
        }
    }
    void getnex2(string &s){
        int len = s.size(),i = 0,j = -1;
        nex2[0] = -1;
        while(i<len){
            if(s[i]==s[j]||j==-1) nex2[++i] = ++j;
            else j = nex2[j];
        }
    }
    bool kmp(string &s,string &m){
        int len = s.size(),len2 = m.size(),i =0,j = 0;
        while(i<len){
            if(s[i]==m[j]||j==-1) i++,j++;
            else j = nex[j];
            if(j==len2) return 1;
        }
        return 0;
    }
    bool kmp2(string &s,string &m){
        int len = s.size(),len2 = m.size(),i =0,j = 0;
        while(i<len){
            if(s[i]==m[j]||j==-1) i++,j++;
            else j = nex2[j];
            if(j==len2) return 1;
        }
        return 0;
    }
    int main(){
        IO;
        string s;cin>>s;
        getnex(s);
        int n,len = s.size();cin>>n; 
        forn(i,n){
            string m;cin>>m;
            int len2 = m.size();
            if(len==len2){
                if(kmp(m,s)) cout<<"jntm!"<<'
    ';
                else cout<<"friend!"<<'
    ';
            }else if(len>len2){
                getnex2(m);
                if(kmp2(s,m)) cout<<"my child!"<<'
    ';
                else cout<<"oh, child!"<<'
    ';
            }else{
                if(kmp(m,s)) cout<<"my teacher!"<<'
    ';
                else cout<<"senior!"<<'
    ';
            }
        }
        return 0;
    }
    

    G.
    题意:一个字符串,1e5. 查询所有子串满足回文串的情况下ans+=不同字符数,求总ans
    思路:马拉车,算每个字符串对半径的贡献
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int maxn = 3e5+5;
    const int inf = 2e9;
    string s;
    char ma[maxn<<1];
    int mp[maxn<<1],last[26];
    
    void manacher(string &s,int len){
        int p = 0,r = 0,mid = 0;
        ma[p++] = '$',ma[p++] ='#';
        forn(i,len) ma[p++] = s[i],ma[p++] = '#';
        forn(i,p){
            mp[i] = r>i?min(mp[(mid<<1)-i],r-i):1;
            while(ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++;
            if(i+mp[i]>r) r = i+mp[i],mid = i;
        }
    }
    
    int main(){
        IO;
        cin>>s;
        forn(i,26) last[i] = -inf;
        int len = s.size();
        manacher(s,len);    
        len = (len+1)<<1;
        ll res = 0;
        for(int i = 2;i<len;i++){
            bool ok = 0;
            int now = i-2>>1;
            if(ma[i]!='#') last[ma[i]-'a'] = i,ok = 1;
            if(ok){
                int lim = mp[i]+1>>1;
                forn(j,26){
                    if(last[j]==-inf) continue;
                    int l = last[j]-2>>1;
                    if(now-l+1<=lim) res+=lim-now+l;
                }
            }
            else{
                int lim = mp[i]>>1;
                if(!lim) continue;
                forn(j,26){
                    if(last[j]==-inf) continue;
                    int l = last[j]-2>>1;
                    if(now-l+1<=lim) res+=lim-now+l;
                }
            }
        }
        cout <<res<<'
    ';
        return 0;
    }
    

    I题
    题意:给一个1e5n的全排列数组,查询1e5段区间满足min(a[i],a[j])==gcd(a[i],a[j])的个数(i,j在区间内)
    思路:共有nlogn对,之后二维偏序,找x,y的右下角。排序y,用树状数组维护x,更新答案。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int maxn = 1e5+5;
    
    int a[maxn],pos[maxn],ans[maxn],n,m;
    struct Q{
        int x,y,id;
    }q[maxn*20];
    bool cmp(Q a,Q b){
        if(a.y==b.y){
            return a.id<b.id;
        }
        return a.y<b.y;
    }
    struct BIT{
        ll node[maxn];
        ll lb(ll x){return x&(-x);}
        void init(){forn(i,maxn)node[i] = 0;}
        void update(ll pos,ll v){for(ll i = pos;i<=n;i+=lb(i))node[i]+=v;}
        ll ask(ll pos){ll sum = 0;for(ll i = pos;i;i-=lb(i))sum+=node[i];return sum;}
        ll query(ll l,ll r){return ask(r)-ask(l-1);}
    }bit;
    int main(){
        IO;
        cin>>n>>m;
        for1(i,n){
            cin>>a[i];
            pos[a[i]] = i;
        }
        int cnt = 0;
        for(int i = 1;i<=n;i++){
            for(int j = i+i;j<=n;j+=i){
                int l = pos[i],r = pos[j];
               // cerr<<i<<' '<<j<<' '<<l<<' '<<r<<'
    ';
                q[cnt++] = {min(l,r),max(l,r),-1};
            }
        }
        forn(i,m){
            int l,r;cin>>l>>r;
            q[cnt++] = {l,r,i};
        }
        sort(q,q+cnt,cmp);
        forn(i,cnt){
            //cerr<<"!@#!@#!@#        "<<q[i].x<<' '<<q[i].y<<' '<<q[i].id<<'
    ';
            if(q[i].id==-1) bit.update(q[i].x,1);
            else ans[q[i].id] = bit.query(q[i].x,q[i].y);
        }
        forn(i,m) cout<<ans[i]<<'
    ';
        return 0;
    }
    /*
    9 10
    5 2 8 3 9 6 7 1 4
    1 2
    1 6
    1 5
    5 8
    2 9
    4 8
    7 6
    2 8
    9 9
    8 9
    
    0
    4
    2
    3
    13
    6
    0
    10
    0
    1
    */
    

    M
    题意:两个字符串,求用第一个构造出字典序大于第二个字符串的最长子序列。
    思路:模拟,有点坑,没搞懂字典序,注意判断最后一位。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int inf = 2e9+5;
    const int maxn = 1e6+5;
    
    int a[maxn][26];
    
    int main(){
        IO;
        int n,m;cin>>n>>m;
        string s,mm;cin>>s>>mm;
        //if(s==mm) return cout<<n-1<<'
    ',0;
        //int n = s.size(),m = mm.size();
        forn(i,26) a[n][i] = inf;
        for(int i = n-1;i>=0;i--){
            forn(j,26) a[i][j] = a[i+1][j];
            a[i][s[i]-'a'] = i;        
        }
        ll now = 0,j = 0,ans = -1;
        while(now<n){
            int x = mm[j]-'a',p = inf;
            for(int i = x+1;i<26;i++){
                p = min(p,a[now][i]);
            }
            ans = max(ans,n-p+j);
            if(a[now][x]>=p)break;
            if(j==m-1){
               // cerr<<"!@#"<<now<<' '<<j+n-a[now][x]<<'
    ';
                if(a[now][x]+1!=n) ans = max(ans,j+n-a[now][x]);
                //else ans = max(ans,j+n-a[now][x]);
                break;
            }
            now = a[now][x]+1;
            j++;
        }
        cout << ans<<'
    ';
        return 0;
    }
    
    1. 南昌网路赛
      B. 题意n个点,m条边的无向带权图,现在有一个超人在s点,和k个消防队在ki个点,超人的速度是消防队的c倍。求超人到达所有点的最短时间中取最大值,消防队到达所有点的最短时间中取最大值,求谁更快。快的一方输出最短路长度(不是最短时间)
      思路:然后建一个新点可以走到所有消防队,求最短路。
      代码:
    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int maxn = 1005;
    const int inf = 2e9+5;
    int d[maxn],vis[maxn],a[maxn];
    vector<pair<int,int> >e[maxn];
    void init(){
        forn(i,maxn){
            e[i].clear();
            d[i] = inf;
            vis[i] = 0;
        }
    }   
    
    void dij(int s){
        forn(i,maxn) d[i] = inf,vis[i] = 0;
        priority_queue<pair<int,int> >q;
        d[s] = 0;
        q.push({0,s});
        while(!q.empty()){
            auto now = q.top();q.pop();
            int u = now.second,w = now.first;
            if(vis[u]) continue;
            vis[u] = 1;
            for(auto x:e[u])if(!vis[x.first]){
                int v = x.first,y = x.second;
                if(d[v]>y-w){
                    d[v] = y-w;
                    q.push({w-y,v});
                }
            }
        }
    }
    
    int main(){
        IO;
        int t;cin>>t;
        while(t--){
            init();
            int n,m,s,k,c;cin>>n>>m>>s>>k>>c;
            forn(i,k) cin>>a[i];
            forn(i,m){
                int x,y,z;cin>>x>>y>>z;
                e[x].push_back({y,z});
                e[y].push_back({x,z});
            }
            int ans = 0,ans2 = 0;
            dij(s);
            for1(i,n) ans = max(ans,d[i]);
            forn(i,k) e[0].push_back({a[i],0});
            dij(0);
            for1(i,n) ans2 = max(ans2,d[i]);
            if(ans<=ans2*c) cout<<ans<<'
    ';
            else cout<<ans2<<'
    ';
        }
        return 0;
    } 
    

    沈阳B题 并查集建图
    这题很难读懂,读懂之后我们缩点建图,怪物点作为隔绝的墙,其他联通都用并查集连起来。然后在新图跑一边即可。
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int maxn = 1e5+5;
    int n,m,k;
    int par[maxn],rankk[maxn];
    bool vis[maxn];
    vector<pair<int,int> >e[maxn];
    map<pair<int,int>,int>mp;
    void init(){
        forn(i,n+1) {
            par[i] = i;
            rankk[i] = 1;
            vis[i] = 0;
            e[i].clear();
        }  
        mp.clear();
    }
    int find(int x){
        return par[x] == x?x:par[x] = find(par[x]);
    }
    void unit(int x,int y){
        x = find(x),y = find(y);
        if(x==y) return;
        if(rankk[x]<rankk[y])swap(x,y);
        par[y] = x;
        rankk[x] += rankk[y];
    }
    int main(){
        IO;cout.precision(10);cout<<fixed;
        int t;cin>>t;
        while(t--){
            cin>>n>>m>>k;
            init();
            forn(i,m){
                int x,y;cin>>x>>y;
                if(x>y)swap(x,y);
                mp[{x,y}]++;
            }
            forn(i,k) {
                int x;cin>>x;
                vis[x] = 1;
            }
            for(auto &x:mp){
                auto &z = x.first;
                if(vis[z.first]||vis[z.second]) continue;
                unit(z.first,z.second);
            }
            for(auto &x:mp){
                int y = x.first.first,z = x.first.second;
                y = find(y),z = find(z);
                if(z!=y){
                    e[y].push_back({z,x.second});
                    e[z].push_back({y,x.second});
                }
            }
            double ans = 0;
            int root = find(1);
            for(auto &x:e[root]){
                ll sum = 0;
                double res = 0;
                int u = x.first;
                for(auto &v:e[u]) sum+=v.second;
                for(auto &v:e[u]){
                    double tem = (1.0*rankk[v.first]*v.second)/sum;
                    if(v.first!=root&&!vis[v.first]) res+=tem;
                }
                ans = max(res,ans);
            }
            ans+=rankk[root];
            cout<<ans<<'
    ';
        }
    
        return 0;   
    }
    

    19上海 G Substring
    Hash 好题 已单独写了一篇

    #include <bits/stdc++.h>
    using namespace std;
    #define ull unsigned long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0)
    const int maxn = 2e4+5;
    const int maxm = 1e5+5;
    const int seed = 131;
    
    unordered_map<ull,int>mp[26][26];
    unordered_map<ull,bool>vis[26][26];
    string z,s;
    int ans[maxn],n;
    ull p[30];
    struct Q{
        int id,len,l,r;
        ull has;
    }q[maxn];
    bool cmp(Q a,Q b){
        return a.len<b.len;
    }
    
    void getans(int x){
        if(x>n) return;
        int l = 0,r = 0;
        ull res = 0;
        while(r<x) res+=p[s[r]-'a'],r++;
        if(vis[s[l]-'a'][s[r-1]-'a'].count(res)) mp[s[l]-'a'][s[r-1]-'a'][res]++;
        while(r<n){
            res-=p[s[l]-'a'],l++,res+=p[s[r]-'a'];
            if(vis[s[l]-'a'][s[r]-'a'].count(res)) mp[s[l]-'a'][s[r]-'a'][res]++;
            r++;
        }
    }
    
    void init(){
        forn(i,26) forn(j,26) mp[i][j].clear(),vis[i][j].clear();
    }
    
    int main(){
    	IO;
    	p[0] = 1;
    	for1(i,26) p[i] = p[i-1]*seed;
    	int t;cin>>t;
    	while(t--){
    		cin>>s;
            init();
            n = s.size();
    		int m;cin>>m;
    		for1(i,m) {
                cin>>z;
                int len = z.size();
                q[i].len = len;
                q[i].id = i;
                q[i].l = z[0]-'a';
                q[i].r = z[len-1]-'a';
                q[i].has = 0;
                forn(j,len) {
                    q[i].has+=p[z[j]-'a'];
                    //cerr<<z[j]-'a'<<' '<<p[z[j]-'a']<<"@!#"<<'
    ';
                }
                //cerr<<len<<' '<<p[0]<<' '<<q[i].has<<'
    ';
                vis[q[i].l][q[i].r][q[i].has] = true;
            }
            sort(q+1,q+m+1,cmp);
            for1(i,m){
               // cerr<<q[i].l<<' '<<q[i].r<<' '<<q[i].has<<'
    ';
                if(q[i].len!=q[i-1].len) getans(q[i].len);
                ans[q[i].id] = mp[q[i].l][q[i].r][q[i].has];
            }
            for1(i,m) cout<<ans[i]<<'
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    SpringBoot中使用Redis
    SpringBoot中实现事务
    SpringBoot中集成持久层框架Mybatis
    JavaScript遍历数组、对象
    web面试(一)
    create-react-app初始化报错及配置less
    JavaScript异步(SuperAgent , isomorphic-fetch)
    JavaScript数组
    JavaScript(token,cookie)
    JavaScript时间段重叠
  • 原文地址:https://www.cnblogs.com/AlexPanda/p/12520298.html
Copyright © 2011-2022 走看看