1. 程式人生 > 實用技巧 >《Codeforces Round #661 (Div. 3)》

《Codeforces Round #661 (Div. 3)》

A:讀錯題導致難度飆升。

這裡題意是任意兩個下標滿足條件都能換,那就是個水題了

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e5+5;
const int M = 1e6+5;
const LL Mod = 998244353;
#define rg register
#define pi acos(-1)
#define INF 1e8
#define
INM INT_MIN #define dbg(ax) cout << "now this num is " << ax << endl; 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; } int a[55],vis[105]; int main() { int ca;ca = read(); while(ca--) { int n;n = read(); memset(vis,0,sizeof(vis)); for(int i = 1;i <= n;++i) { a[i] = read(); vis[a[i]]++; } sort(a+1,a+n+1); int f = 0
; for(int i = 1;i < n;++i) { if(vis[a[i]+1] != 0) continue; if(vis[a[i]] > 1){vis[a[i]]--;continue;} f = 1; } if(f) printf("NO\n"); else printf("YES\n"); } // system("pause"); return 0; }
View Code

B:水題

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e3+5;
const int M = 1e6+5;
const LL Mod = 998244353;
#define rg register
#define pi acos(-1)
#define INF 1e18
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read()
{
    LL 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;
}
LL a[55],b[55];
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        int n;n = read();
        LL mi1 = INF,mi2 = INF;
        for(int i = 1;i <= n;++i) a[i] = read(),mi1 = min(mi1,a[i]);
        for(int i = 1;i <= n;++i) b[i] = read(),mi2 = min(mi2,b[i]);
        LL ans = 0; 
        for(int i = 1;i <= n;++i)
        {
            int dis = a[i]-mi1;
            ans += dis;
            int ma = b[i]-mi2;
            if(ma > dis) ans += ma-dis;   
       //     dbg(ans);
        }
        printf("%lld\n",ans);
    }
   // system("pause");
    return 0;
}
View Code

C:一開始想到二分,但發現不滿足二分性質。

但是這也為解題提供了一個思路,可以發現組合的權值最多隻有[1,100]的可能性,那麼取列舉這個權值即可

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e3+5;
const int M = 1e6+5;
const LL Mod = 998244353;
#define rg register
#define pi acos(-1)
#define INF 1e18
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
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;
}
int w[55],n,vis[105],num[105];
int check(int x)
{
    for(int i = 0;i <= 100;++i) num[i] = vis[i];
    int ans = 0;
    for(int i = 1;i <= n;++i)
    {
        if(w[i] > x) continue;
        if(x-w[i] == w[i])
        {
            if(num[w[i]] > 1) num[w[i]] -= 2,ans++;
        }
        else if(num[x-w[i]] > 0 && num[w[i]] > 0)
        {
            num[x-w[i]]--;
            num[w[i]]--;
            ans++;
        }
    }
    return ans;
}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        n = read();
        memset(vis,0,sizeof(vis));
        for(int i = 1;i <= n;++i) w[i] = read(),vis[w[i]]++;
        int ans = 0;
        for(int i = 1;i <= 100;++i) ans = max(ans,check(i));
        printf("%d\n",ans);
    }
  //  system("pause");
    return 0;
}
View Code

D:感覺我想的稍微麻煩了。。能AC就是好題解(逃

可以發現對於每個1,我們要將後面的沒有被接入的第一個0接入當前序列。(0也是同理)

這樣顯然是可以滿足最小的子序列數的。

那麼對於這個後面的最小位置,我們可以用線段樹維護這個位置。

然後一個位置被接入,就去更新線段樹。因為是單點更新,複雜度nlogn,也挺快了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 2e5+5;
const int M = 1e6+5;
const LL Mod = 998244353;
#define rg register
#define pi acos(-1)
#define INF 1e8
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
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;
}
int ans[N];//0,1
char s[N];
struct Node{int L,r,mi;}node[2][N<<2];
void build(int L,int r,int idx,int id)//id-0,id-1
{
    node[id][idx].L = L,node[id][idx].r = r;
    if(L == r)
    {
        if(s[L] == '0' && id == 0 || s[L] == '1' && id == 1) node[id][idx].mi = L;
        else node[id][idx].mi = INF;
        return ;
    }
    int mid = (L+r)>>1;
    build(L,mid,idx<<1,id);
    build(mid+1,r,idx<<1|1,id);
    node[id][idx].mi = min(node[id][idx<<1].mi,node[id][idx<<1|1].mi);
}
void update(int x,int idx,int id)
{
    if(node[id][idx].L == node[id][idx].r)
    {
        node[id][idx].mi = INF;
        return ;
    }
    int mid = (node[id][idx].L + node[id][idx].r)>>1;
    if(mid >= x) update(x,idx<<1,id);
    else update(x,idx<<1|1,id);
    node[id][idx].mi = min(node[id][idx<<1].mi,node[id][idx<<1|1].mi);
}
int query_mi(int L,int r,int idx,int id)
{
    if(node[id][idx].L >= L && node[id][idx].r <= r) return node[id][idx].mi;
    int mid = (node[id][idx].L+node[id][idx].r)>>1,mi = INF;
    if(mid >= L) mi = min(mi,query_mi(L,r,idx<<1,id));
    if(mid < r) mi = min(mi,query_mi(L,r,idx<<1|1,id));
    return mi;
}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        int n;n = read();
        scanf("%s",s+1);
        build(1,n,1,0);
        build(1,n,1,1);
        int ma = 0;
        memset(ans,0,sizeof(ans));
        for(int i = 1;i <= n;++i)
        {
            if(ans[i] == 0) ans[i] = ++ma;
            int tmp;
            if(s[i] == '0') tmp = query_mi(i+1,n,1,1);
            else tmp = query_mi(i+1,n,1,0);
            if(tmp == INF) continue;
            ans[tmp] = ans[i];
            if(s[tmp] == '0') update(tmp,1,0);
            else update(tmp,1,1);
        }
        printf("%d\n",ma);
        for(int i = 1;i <= n;++i) printf("%d%c",ans[i],i == n ? '\n' : ' ');
    }
    //system("pause");
    return 0;
}
View Code

E1:讀錯題導致難度飆升(梅開二度,老笨蛋了)

注意的是,這裡是要使總(root-leaves)路徑權值和小於s。

那麼,我們可以去記錄路徑被經過的次數,然後乘上這個路徑的w-w/2,這就是讓它折半一次的能對總權值減少的貢獻。

那麼顯然我們每次都選最大的,就能在最少的次數內滿足。

這裡這個被經過次數很顯然就是子節點數。堆來維護最大值即可

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e5+5;
const int M = 1e6+5;
const LL Mod = 998244353;
#define rg register
#define pi acos(-1)
#define INF 1e18
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read()
{
    LL 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;
}
struct Node{int to;LL dis;};
vector<Node> G[N];
int ssize[N];
LL sum = 0;
struct Point{
    LL cost,w,cnt;
    bool operator < (const Point &a)const{
        return cost < a.cost;
    }
};
priority_queue<Point> Q;
LL cal(LL w,int cnt)
{
    return 1LL*cnt*(w-w/2);
}
void dfs(int u,int fa,LL dis)
{
    if(G[u].size() == 1) ssize[u] = 1;
    for(auto v : G[u])
    {
        if(v.to == fa) continue;
        dfs(v.to,u,v.dis);
        ssize[u] += ssize[v.to];
    }
    if(dis != 0) 
    {
        //printf("dis is %lld u is %d ssize is %d\n",dis,u,ssize[u]);
        sum += 1LL*ssize[u]*dis;
        Q.push(Point{cal(dis,ssize[u]),dis,ssize[u]});
    }
}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        int n;LL s;
        n = read(),s = read();
        for(rg int i = 1;i <= n;++i) G[i].clear(),ssize[i] = 0;
        for(rg int i = 1;i < n;++i)
        {
            int u,v;LL w;
            u = read(),v = read(),w = read();
            G[u].push_back(Node{v,w});
            G[v].push_back(Node{u,w});
        }
        while(!Q.empty()) Q.pop();
        sum = 0;
        dfs(1,0,0);
        int ans = 0;
        while(!Q.empty() && sum > s)
        {
            ans++;
            Point q = Q.top();
            Q.pop();
            sum -= q.cost;
            q.w /= 2;
            q.cost = cal(q.w,q.cnt);
            Q.push(q);
        }
        printf("%d\n",ans);
    }
   // system("pause");
    return 0;
}
View Code

E2:最小化花費了,可以用二分來。

因為c只有1,2,那麼我們可以去維護兩個堆。

一個維護1,一個維護2。開兩個字首和陣列

用陣列1來維護花費代價為i時能減少的最大權值。

陣列2來維護花費代價為2*i時能減少的最大權值。

我們列舉1的花費,然後去二分最小的2代價使得sum-兩個字首和陣列和 <= s

memset初始化陣列T了,其實沒必要,只要讓第0個為0即可(改了之後快的飛起~~蕪湖)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<LL,int> pii;
const int N = 1e5+5;
const int M = 2e6+5;
const LL Mod = 998244353;
#define rg register
#define pi acos(-1)
#define INF 1e18
#define INM INT_MIN
#define dbg(ax) cout << "now this num is " << ax << endl;
inline LL read()
{
    LL 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;
}
struct Node{int to;LL dis,cost;};
vector<Node> G[N];
struct Point{
    int cnt;LL w,cost;
    bool operator < (const Point &a)const{
        return cost < a.cost;
    }
};
LL cal(LL w,int cnt)
{
    return 1LL*cnt*(w-w/2);
}
priority_queue<Point> Q1,Q2;
int ssize[N];
LL sum = 0,pre1[M],pre2[M],s;
void dfs(int u,int fa,LL dis,int c)
{
    if(G[u].size() == 1) ssize[u] = 1;
    for(auto v : G[u])
    {
        if(v.to == fa) continue;
        dfs(v.to,u,v.dis,v.cost);
        ssize[u] += ssize[v.to];
    }
    if(dis != 0)
    {
        sum += 1LL*ssize[u]*dis;
        if(c == 1) Q1.push(Point{ssize[u],dis,cal(dis,ssize[u])});
        else Q2.push(Point{ssize[u],dis,cal(dis,ssize[u])});
    }
}
bool check(LL tmp,int x)
{
    return (tmp-pre2[x]) <= s;
}
int main()
{
    int ca;ca = read();
    while(ca--)
    {
        int n;
        n = read(),s = read();
        for(int i = 1;i <= n;++i) G[i].clear(),ssize[i] = 0;
        for(rg int i = 1;i < n;++i)
        {
            int u,v,w,c;
            u = read(),v = read(),w = read(),c = read();
            G[u].push_back(Node{v,w,c});
            G[v].push_back(Node{u,w,c});
        }
        while(!Q1.empty()) Q1.pop();
        while(!Q2.empty()) Q2.pop();
        pre1[0] = pre2[0] = sum = 0;
        dfs(1,0,0,0);
        int cnt1 = 0,cnt2 = 0;
        while(!Q1.empty() && sum-pre1[cnt1] > s)
        {
            Point q = Q1.top();Q1.pop();
            ++cnt1;
            pre1[cnt1] = pre1[cnt1-1]+q.cost;
            q.w /= 2;
            q.cost = cal(q.w,q.cnt);
            if(q.cost != 0) Q1.push(q);
        }
        while(!Q2.empty() && sum-pre2[cnt2] > s)
        {
            Point q = Q2.top();Q2.pop();
            ++cnt2;
            pre2[cnt2] = pre2[cnt2-1]+q.cost;
            q.w /= 2;
            q.cost = cal(q.w,q.cnt);
            if(q.cost != 0) Q2.push(q);
        }
        LL ans = INF;
        for(int i = 0;i <= cnt1;++i)
        {
            LL ma = sum-pre1[i];
            int L = 0,r = cnt2,ta = 1e8;
            while(L <= r)
            {
                int mid = (L+r)>>1;
                if(check(ma,mid))
                {
                    ta = mid;
                    r = mid-1;
                } 
                else L = mid+1;
            }
            ans = min(ans,1LL*i+ta*2);
        }
        printf("%lld\n",ans);
    }
    //system("pause");
    return 0;
}
View Code

F:待補