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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章