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]<<'\n';
    }
    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)<<'\n';
        }
    }
    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)<<'\n';
    }
    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!"<<'\n';
            else cout<<"friend!"<<'\n';
        }else if(len>len2){
            getnex2(m);
            if(kmp2(s,m)) cout<<"my child!"<<'\n';
            else cout<<"oh, child!"<<'\n';
        }else{
            if(kmp(m,s)) cout<<"my teacher!"<<'\n';
            else cout<<"senior!"<<'\n';
        }
    }
    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<<'\n';
    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<<'\n';
            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<<'\n';
        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]<<'\n';
    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<<'\n',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]<<'\n';
            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<<'\n';
    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<<'\n';
        else cout<<ans2<<'\n';
    }
    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<<'\n';
    }

    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']<<"@!#"<<'\n';
            }
            //cerr<<len<<' '<<p[0]<<' '<<q[i].has<<'\n';
            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<<'\n';
            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]<<'\n';
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章