《补题solution》

出题人卡的真的好.

宇佐大人的白旗 ~ Most Famous Hero:

这题有点无语了,比赛的时候数据出问题了,害我一直出问题,最后数据修了就过了。

做法1:直接最短路上更新就好了。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N = 1e4 + 5;
const int M = 2e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline int read(){
        int x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

int n,m,c[N],p[N],s,t;
LL dis[N];
struct Node{int to,dis;};
vector<Node> G[N];

void solve() {
    for(int i = 1;i <= n;++i) dis[i] = INF;
    priority_queue<pii,vector<pii>,greater<pii> > Q;
    dis[s] = c[s] - p[s];
    Q.push(pii{dis[s],s});
    while(!Q.empty()) {
        int u = Q.top().second;
        LL d = Q.top().first;
        Q.pop();
        if(d > dis[u]) continue;
        for(auto v : G[u]) {
            LL tmp = dis[u] + v.dis;
            LL ma = tmp + c[v.to] - p[v.to];
            if(v.to == t || ma < tmp) tmp = ma;
            if(tmp < dis[v.to]) {
                dis[v.to] = tmp;
                Q.push(pii{dis[v.to],v.to});
            }
        }
    }
}   
int main() {
    n = read(),m = read();
    for(int i = 1;i <= n;++i) c[i] = read();
    for(int i = 1;i <= n;++i) p[i] = read();
    while(m--) {
        int u,v,w;u = read(),v = read(),w = read();
        G[u].push_back(Node{v,w});
    }
    s = read(),t = read();
    solve();
    printf("%lld\n",dis[t]);
   // system("pause");
    return 0;
}
View Code

做法2:当数据量变大,做法1的复杂度可能就会比较高,因为这条线路一定从S出发,到T结束。

那么就以S为根来建一棵树,注意是有向的,也就是有向无环图,然后就可以拓扑排序了。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N = 1e4 + 5;
const int M = 2e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline int read(){
        int x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

int n,m,c[N],p[N],s,t,in[N],a[N];
LL dis[N];
bool vis[N];
struct Node{int to,dis;};
vector<Node> G[N],vec[N];

void dfs(int u) {
    vis[u] = 1;
    for(auto v : G[u]) {
        if(!vis[v.to]) {
            dfs(v.to);
        }
    }
}
void solve() {
    for(int i = 1;i <= n;++i) dis[i] = INF;
    queue<int> Q;
    Q.push(s);
    dis[s] = 0;
    while(!Q.empty()) {
        int u = Q.front();
        Q.pop();
        for(auto v : vec[u]) {
            in[v.to]--;
            LL ma = dis[u] + v.dis;
            if(v.to != s && v.to != t && a[v.to] <= 0) ma += a[v.to];
            dis[v.to] = min(dis[v.to],ma);
            if(in[v.to] == 0) {
                Q.push(v.to);
            }
        }
    }
}
int main() {
    n = read(),m = read();
    for(int i = 1;i <= n;++i) c[i] = read();
    for(int i = 1;i <= n;++i) p[i] = read(),a[i] = c[i] - p[i];
    while(m--) {
        int u,v,w;u = read(),v = read(),w = read();
        G[u].push_back(Node{v,w});
    }
    s = read(),t = read();
    dfs(s);
    for(int i = 1;i <= n;++i) {
        if(vis[i] == 0) continue;
        for(auto v : G[i]) {
            if(vis[v.to] == 0) continue;
            vec[i].push_back(Node{v.to,v.dis});
            in[v.to]++;
        }
    }
    solve();
    printf("%lld\n",dis[t] + a[s] + a[t]);
  //  system("pause");
    return 0;
}
View Code

 飘上月球不死之烟 ~ Elixir of Life:

很裸的线段树,但是这里内存卡的很紧,如果用结构体来建树,就会爆内存。

所以就用数组来,同时,这里普通的线段树常数卡的好,也能过。

我们考虑对线段树进行一些优化。

首先很显然可以想到倒着进行修改,那么一个被修改过的位置,它的大小写就固定了。我们就打上标记。

对于一个位置最多修改一下,这样平推下来复杂度就是nlogn。

同时最后我们一直query就下放所有颜色, 这样比遍历然后单点询问要快一点。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N = 1e6 + 5;
const int M = 2e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
#define DBG(bx,ax) cout << bx << " is " << ax << endl;
namespace FASTIO{
    inline int read(){
        int x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

int m,tag[N << 2],k[N << 2],sum[N << 2];
int id[N],L[N],r[N];
void Pushup(int idx) {
    sum[idx] = sum[idx << 1] + sum[idx << 1 | 1];
}
void Pushdown(int L,int r,int idx) {
    if(tag[idx] != 0) {        
        int mid = (L + r) >> 1;
        if(sum[idx << 1] != mid - L + 1) {
            sum[idx << 1] = mid - L + 1;
            tag[idx << 1] = tag[idx];
            k[idx << 1] = tag[idx];
        } 
        if(sum[idx << 1 | 1] != r - mid) {
            sum[idx << 1 | 1] = r - mid;
            tag[idx << 1 | 1] = tag[idx];
            k[idx << 1 | 1] = tag[idx];
        }
        tag[idx] = 0;
    }
}
void update(int le,int ri,int L,int r,int idx,int val) {
    if(le >= L && ri <= r) {
        tag[idx] = k[idx] = val;
        sum[idx] = ri - le + 1;
        return ;
    }
    Pushdown(le,ri,idx);
    int mid = (le + ri) >> 1;
    if(mid >= L) {
        if(sum[idx << 1] != mid - le + 1) {
            update(le,mid,L,r,idx << 1,val);
        }
    }
    if(mid < r) {
        if(sum[idx << 1 | 1] != ri - mid) update(mid + 1,ri,L,r,idx << 1 | 1,val);
    }
    Pushup(idx);
}
void query(int L,int r,int idx) {
    if(L == r) {
        id[L] = k[idx];
        return ;
    }
    Pushdown(L,r,idx);
    int mid = (L + r) >> 1;
    if(sum[idx << 1] != 0) query(L,mid,idx << 1);
    if(sum[idx << 1 | 1] != 0) query(mid + 1,r,idx << 1 | 1);
}
char cal1(char c) {
    if(c >= 'a' && c <= 'z') return c;
    else return c + 32;
}
char cal2(char c) {
    if(c >= 'A' && c <= 'Z') return c;
    else return c - 32;
}
int main() {
    m = read();
    string s;getline(cin,s);
    int n = s.size();
    for(int i = 1;i <= m;++i) id[i] = read(),L[i] = min(n,read()),r[i] = min(n,read());
    for(int i = m;i >= 1;--i) {
        update(1,n,L[i],r[i],1,id[i]);
    }
    memset(id,0,sizeof(id));
    query(1,n,1);
    for(int i = 1;i <= n;++i) {
        //printf("i is %d val is %d\n",i,id[i]);
        if(s[i - 1] == ' ') printf(" ");
        else {
            if(id[i] == 0) printf("%c",s[i - 1]);
            else if(id[i] == 1) printf("%c",cal1(s[i - 1]));
            else if(id[i] == 2) printf("%c",cal2(s[i - 1]));
            else {
                if(i == 1) printf("%c",cal2(s[i - 1]));
                else if(s[i - 2] == ' ') printf("%c",cal2(s[i - 1]));
                else printf("%c",cal1(s[i - 1]));
            }
        }
    }   
    //system("pause");
    return 0;
}
/*
5
ABC DADN A adi da D
1 3 3
1 3 10
3 3 10
2 2 10
1 2 2
*/
View Code

Locked Girl ~ 少女密室:

那么我们可以考虑当前完成了所有删除操作,然后只需要添加操作即可。

显然如果要删除后的代码1,添加一些就可以得到代码2。

那么这段删除后的代码,一定是代码1和代码2的公共子序列。

假设删去的长度为x,代码1长度len1,代码2长度len2。

那么对于需要添加的字符串长度就是len2 - (len1 - x) = len1 - len2 + x就是操作的数量。

那么我们需要操作的次数就是len1 - len2 + 2 * x.

显然x越小,我们操作的次数越小,x越小也就是表示要公共子序列越大,那么很显然就是求最长公共子序列了。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N = 1e6 + 5;
const int M = 2e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
#define DBG(bx,ax) cout << bx << " is " << ax << endl;
namespace FASTIO{
    inline int read(){
        int x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

int dp[305][305],n,m;
string a[305],b[305];
int main() {
    n = read();
    for(int i = 1;i <= n;++i) getline(cin,a[i]);
    m = read();
    for(int i = 1;i <= m;++i) getline(cin,b[i]);
    for(int i = 1;i <= n;++i) {
        for(int j = 1;j <= m;++j) {
            if(a[i] == b[j]) dp[i][j] = max(dp[i][j],dp[i - 1][j - 1] + 1);
            else dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);
        }
    }
    int ans = n - dp[n][m] + m - dp[n][m];
    printf("%d\n",ans);
  //  system("pause");
    return 0;
}
View Code

回忆京都 ~ Retrospective Kyoto:

这题还是有点意思的,要推到结论需要思考时间。

首先,对于该图的任意一棵生成树tree(所有点都在该树上),都必定存在一种方法满足条件。

方法就是从叶子开始往上走,每次都从父亲走到儿子,注意要一个父节点的所有儿子都走完,再将这个父节点往上。

dfs来找一棵生成树即可。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e6 + 5;
const int M = 2e3 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e18
#define dbg(ax) cout << "now this num is " << ax << endl;
#define DBG(bx,ax) cout << bx << " is " << ax << endl;
namespace FASTIO{
    inline int read(){
        int x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;

vector<int> G[N];
bool vis[N];
vector<pii> ans;
void dfs(int u) {
    vis[u] = 1;
    for(auto v : G[u]) {
        if(!vis[v]) {
            ans.push_back(pii{u,v});
            dfs(v);
        }
    }
}

int main() {
    int n,m;n = read(),m = read();
    while(m--) {
        int u,v;u = read(),v = read();
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1);
    if(ans.size() != n - 1) printf("Impossible!\n");
    else {
        for(int i = ans.size() - 1;i >= 0;--i) {
            printf("%d -> %d\n",ans[i].first,ans[i].second);
        }
    }
    //system("pause");
    return 0;
}
View Code

青木原的传说 ~ Forbidden Forest:

这题卡vector,最后用了链式前向星才过的。

一开始看成连通块一起减导致贪心错误,换根的思路也误导了自己。

这里正确的贪心思路应该是从叶子节点往上。

我们考虑对于节点u,它的子树已经完成了归0,那么节点u它的消去路径,只有两种情况。

1:从u往fa走的一条链。

2:从u到fa另一个子节点v的一条链。

这里方案2一次可以减少两个儿子的1,然后方案1只能减少一个儿子的1,所以方案2肯定比方案1优。

那么我们在能用方案2的时候就尽量用方案2.

将所有子节点的贡献放入大顶堆,大顶堆能保证我们最后实行方案1,可操作的子节点值是最大的,这样就能最大化利用u的这条链。

这里在堆里操作的时候每次都要一个一个减,然后重新放入堆,这样也是为了保证最后得到的堆顶的子节点值是当前最优的。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pii;
const int N = 5e5 + 5;
const int M = 2e3 + 5;
const LL Mod = 100000007;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;

int n,m,a[N];
LL ans = 0;
bool vis[N];
int head[N],tot = 0;
struct Node{int to,next;}e[N << 1];
void add(int u,int v) {
    e[++tot].to = v,e[tot].next = head[u],head[u] = tot;
    e[++tot].to = u,e[tot].next = head[v],head[v] = tot;
}
void dfs(int u,int fa) {
    vis[u] = 1;
    priority_queue<int,vector<int>,less<int> > Q;
    for(int i = head[u];i;i = e[i].next) {
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v,u);
        if(a[v] != 0) Q.push(a[v]);
    }
    while(a[u] != 0 && Q.size() > 1) {
        int x = Q.top();
        Q.pop();
        int y = Q.top();
        Q.pop();
        x--,y--,ans--,a[u]--;
        if(x != 0) Q.push(x);
        if(y != 0) Q.push(y);
    }
    ans += a[u];
    if(Q.size() > 0) {
        int x = Q.top();
        Q.pop();
        if(a[u] >= x) ans -= x;
        else ans -= a[u];
    }
}
int main() {
    scanf("%d %d",&n,&m);
    for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
    while(m--) {
        int u,v;scanf("%d %d",&u,&v);
        add(u,v);
    }
    for(int i = 1;i <= n;++i) {
        if(vis[i] == 1) continue;
        dfs(i,0);
    }
    printf("%lld\n",ans);
    system("pause");
    return 0;
}
View Code

 

 

posted @ 2021-08-02 17:20  levill  阅读(38)  评论(0编辑  收藏  举报