主頁 >  其他 > 2020 ACM - ICPC nanjing 南京站 題解(10 / 13)

2020 ACM - ICPC nanjing 南京站 題解(10 / 13)

2021-04-07 10:54:12 其他

整理的演算法模板合集: ACM模板

點我看演算法全家桶系列!!!

實際上是一個全新的精煉模板整合計劃


比賽鏈接:https://codeforces.com/gym/102992

  • A. 構造
  • D. 圖論
  • E. 構造,爆搜
  • F. 期望,三分
  • H. 抽屜原理,爆搜打表,組合計數
  • I. 計算幾何
  • J. 博弈論,吉司機線段樹
  • K. 數論,簽到
  • L. 思維,簽到
  • M. 樹上背包 O ( n 2 ) O(n^2) O(n2)

A、Ah, It’s Yesterday Once More

Problem

對于給定的 n × m n \times m n×m 的方格, 0 0 0 代表障礙, 1 1 1 代表袋鼠,有一串隨機生成的長為 5 × 1 0 4 5 \times 10^4 5×104的指令,僅包含 LRUD \text{LRUD} LRUD 字符,分別表示將所有袋鼠同時向某個方向移動(若能移動,即不經過障礙、不超出方格范圍),現要求構造一個 n × m n \times m n×m 方格圖,使得對于隨機生成的 500 500 500 串指令,至少有 125 125 125 個滿足執行后,所有袋鼠不都在同一個方格,要求構造的袋鼠方格連通、且不含環,

1 ≤ n , m ≤ 20 1 \le n, m \le 20 1n,m20

Solution

我們只需要執行 1 4 \cfrac{1}{4} 41? 的指令執行即可,也就是每只袋鼠至少有一個方向是墻,所以我們可以構造一個不對稱的路徑,以及一些分岔路口,例如一些 Z 字形路徑,注意袋鼠們必須連通以及不能有環,

#include<bits/stdc++.h>
using namespace std;

int main(){
    char ans[21][21] = {
    "20 20",
    "11011111011111011111",
    "10110100110100110100",
    "11101101101101101101",
    "10011011011011011001",
    "10110110110110110111",
    "01101101101101101101",
    "11011011011011011011",
    "10110110110110110110",
    "11101101101101101101",
    "10011011011011011001",
    "10110110110110110111",
    "01101101101101101101",
    "11011011011011011011",
    "10110110110110110110",
    "11101101101101101101",
    "10011011011011011001",
    "10110110110110110111",
    "01101101101101101101",
    "01011001011001011001",
    "11110111110111110111",
    };
    for(int i = 0; i <= 20; ++i){

        cout << ans[i] << endl;
    }
    return 0;
}

D、Degree of Spanning Tree

Problem

給出一個無向圖,尋找它的一棵生成樹,要求生成樹上每個點的度數都要小于等于 n 2 \cfrac{n}{2} 2n?

Solution

首先隨便找到一棵生成樹,尋找它度數最大的點,在所有節點中,度數大于 n 2 \cfrac{n}{2} 2n? 的節點最多只有一個,若找不到直接輸出,找到了則令其為根節點,對所有不在生成樹上的邊進行列舉,若這條邊的起點終點在樹上的lca是根節點,則說明這條邊的加入可以令根節點度數-1,但是在兩個點都是根節點的兒子節點的情況下,會令選擇的另一邊的節點度數+1,所以在刪邊加邊的程序中要判斷是否會導致其他節點度數大于 n 2 \cfrac{n}{2} 2n?

動態加邊刪邊求lca實在是不會…但是還好可以用并查集來做,首先將根節點的所有子樹各自構成集合,集合祖先為根節點的兒子節點,每次遍歷邊查詢兩端點是否在同一集合即可,

Code

#include <bits/stdc++.h>
#define reg register
#define ios ios::sync_with_stdio(false)
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 2e5 + 10;
const double pi = acos(-1.0);
const ll mod = 1e9 + 7;

vector<pair<int,int>> es;
map<pair<int,int>,int> mp;
struct Edge{
    int to,nxt;
}edges[maxn << 2];

int head[maxn], idx;
int deg[maxn];
void add(int u,int v)
{
    edges[idx] = {v,head[u]}, head[u] = idx++;
    edges[idx] = {u,head[v]}, head[v] = idx++;
}
int pre[maxn];
int chose[maxn];

int fi(int x) {return x == pre[x] ? x : pre[x] = fi(pre[x]);}

void dfs(int u,int fa, int sig)
{
    pre[u] = sig;
    for(int i = head[u];~i;i = edges[i].nxt){
        int v = edges[i].to;
        if(v == fa) continue;
        dfs(v,u,sig);
    }
}

void init(int n,int m)
{
    mp.clear();
    es.clear();
    for(int i = 0;i <= n;++i){
        head[i] = -1;
        deg[i] = 0;
        pre[i] = i;
    }
    for(int i = 0;i <= m;++i){
        chose[i] = 0;
    }
    idx = 0;
}

int main()
{
    
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d %d",&n,&m);
        init(n,m);
        for(int i = 0;i < m;++i){
            int u,v;
            scanf("%d%d",&u,&v);
            if(u > v) swap(u,v);
            es.push_back({u,v});
        }
        sort(es.begin(),es.end());
        es.erase(unique(es.begin(),es.end()),es.end());
        m = static_cast<int>(es.size()); // 洗掉重邊自環
        for(int i = 0;i < m;++i){
            int u = es[i].first;
            int v = es[i].second;
            mp[{u,v}] = mp[{v,u}] = i;
            int fu = fi(u),fv = fi(v);
            if(fu != fv){ 
                add(u,v);		//kruskal 建生成樹
                pre[fu] = fv;
                deg[u]++;
                deg[v]++;
                chose[i] = 1;
            }
        }
        int flag = 0;
        for(int i = 2;i <= n;++i){
            if(fi(i) != fi(1))  flag = 1;
        }
        if(flag) {
            puts("No");
            continue;
        }

        int rt = -1;
        for(int i = 1;i <= n;++i){
            if(deg[i] > n/2){
                rt = i;
                break;
            }
        }
        if(rt == -1){
            puts("Yes");
            for(int i = 0;i < m;++i){
                if(chose[i]){
                    printf("%d %d\n",es[i].first,es[i].second);
                }
            }
            continue;
        }
        for(int i = 1;i <= n;++i) pre[i] = i;
        for(int i = head[rt];~i;i = edges[i].nxt){
            dfs(edges[i].to,rt,edges[i].to);
        }
        for(int i = 0;i < m;++i){
            if(chose[i]) continue;
            int u = es[i].first, v = es[i].second;
            int fu = fi(u), fv = fi(v);
            if(fu == fv || u == rt || v == rt) continue;
            deg[rt]--;
            deg[u]++;
            deg[v]++;
            deg[fu]--;
            if(deg[u] > n/2 || deg[v] > n/2){	//檢測是否可行,不可行就恢復
                deg[fu]++;
                deg[fv]--;
                if(deg[u] > n/2 || deg[v] > n/2){
                    deg[rt]++;
                    deg[u]--;
                    deg[v]--;
                    deg[fv]++;
                    continue;
                }
                else{
                    pre[fv] = fu;
                    chose[i] = 1;
                    chose[mp[{rt,fv}]] = 0;
                }
            }
            else{
                pre[fu] = fv;
                chose[i] = 1;
                chose[mp[{rt,fu}]] = 0;
            }
            if(deg[rt] <= n/2) break;
        }
        if(deg[rt] <= n/2){
            puts("Yes");
            for(int i = 0;i < m;++i){
                if(chose[i]){
                    printf("%d %d\n",es[i].first,es[i].second);
                }
            }
        }
        else puts("No");
        
    }

    return 0;
}

E、Evil Coordinate

Problem

在一個直角坐標系中,給定起點 ( 0 , 0 ) (0, 0) (0,0),一個障礙 ( m x , m y ) (m_x, m_y) (mx?,my?) 以及一串長度為 n n n 的指令,僅包含 L / R / U / D \text{L / R / U / D} L / R / U / D 字符,分別表示向左右上下移動,請你調整指令順序讓移動程序不經過 ( m x , m y ) (m_x, m_y) (mx?,my?),有解輸出指令字符,無解輸出 impossible \text{impossible} impossible

1 ≤ n ≤ 1 0 5 , ? 1 0 9 ≤ m x , m y ≤ 1 0 9 , ∑ n i ≤ 1 0 6 1\le n \le 10^5, -10^9 \le m_x, m_y \le 10^9, \sum n_i \le 10^6 1n105,?109mx?,my?109,ni?106

Solution

開始想的是左右走完,然后上下,發現可以先上下再左右,然后又發現反例,然后也可以先左再上再下再右,明白了,所有的方向排列一共有 4 ! = 24 4!=24 4!=24 種,直接求全排列,然后對于每一個排列,分別判斷即可,

最后注意 ios 加速之后 puts 就不能用了…

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 2e5 + 10;
const double pi = acos(-1.0);
const ll mod = 1e9 + 7;

bool cal(int x,int y, int l,int r,int u, int d,vector<int> v)
{
    string res;
    for(int i = 0;i < v.size();++i){
        if(v[i] == 1) while(l--) res.push_back('L');
        if(v[i] == 2) while(r--) res.push_back('R');
        if(v[i] == 3) while(u--) res.push_back('U');
        if(v[i] == 4) while(d--) res.push_back('D');
    }
    int flag = 0;
    int nx = 0,ny = 0;
    for(int i = 0;i < res.size();++i){
        if(res[i] == 'L') nx--;
        if(res[i] == 'R') nx++;
        if(res[i] == 'U') ny++;
        if(res[i] == 'D') ny--;
        if(nx == x && ny == y){
            flag = 1;
        }
    }
    if(!flag) {
        cout<<res<<endl;
        return 1;
    } 
    else return 0;
}


int main()
{
    int t;
    cin>>t;
    while(t--){
        int x,y;
        cin>>x>>y;
        string s;
        cin>>s;
        int l,r,u,d;
        l = r = u = d = 0;
        int nx = 0,ny = 0;
        int flag = 0;
        for(int i = 0;i < s.size();++i){
            if(s[i] == 'L') l++,nx--;
            if(s[i] == 'R') r++,nx++;
            if(s[i] == 'U') u++,ny++;
            if(s[i] == 'D') d++,ny--;
            if(nx == x && ny == y){
                flag = 1;
            }
        }

        if((x == 0 && y == 0) || (x == nx && y == ny)){
            puts("Impossible");
            continue;
        } 
        vector<int> v = {1,2,3,4};
        flag = 0;
        do{
            if(cal(x,y,l,r,u,d,v)){
                flag = 1;
                break;
            }
        }while(next_permutation(v.begin(),v.end()));
        if(!flag) puts("Impossible");
        
    }

    return 0;
}

F、Fireworks

Problem

制作一支煙花需要花費 n n n 分鐘,每支煙花有 p × 1 0 ? 4 p \times 10^{-4} p×10?4的概率是完美的,每次可以花費 m m m 分鐘點燃之前制作的所有煙花,若發現至少有一支完美的,則停止,問最優策略下,最短的停下的時間期望是多少?

多組資料, 1 ≤ T ≤ 1 0 4 , 1 ≤ n , m ≤ 1 0 9 , 1 ≤ p ≤ 1 0 4 1 \le T \le 10^4, 1 \le n, m \le 10^9, 1 \le p \le 10^4 1T104,1n,m109,1p104

Solution

不是完美煙花的概率 q = 1 ? ( p × 1 0 ? 4 ) q = 1 - (p \times 10^{-4}) q=1?(p×10?4),假設最優策略為連續制作 k k k 支煙花后花費 m m m 的時間一次全部點燃,若發現有完美煙花則停止,若沒有則回到初始狀態,繼續執行最優策略,發現實際上求的就是期望最早第幾次成功,也就是前 k ? 1 k-1 k?1 次失敗,第 k k k 次成功發現只有兩種情況,顯然服從幾何分布(前 k ? 1 k-1 k?1 次失敗,第 k k k 次成功 ),即 n n n 重伯努利實驗的幾何概型,根據幾何概型的期望公式得: E ( X ) = 1 1 ? q k E(X) = \cfrac{1}{1 - q^k} E(X)=1?qk1?,期望時間為 f ( k ) = n × k + m 1 ? q k f(k) = \cfrac{n \times k + m}{1 - q^k} f(k)=1?qkn×k+m? ,顯然答案就是峰值,打表發現這是一個單峰函式,直接三分答案即可,或者也可以二分 + 求導,

Code

#include <bits/stdc++.h>
#define reg register
#define ios ios::sync_with_stdio(false)
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-9;
const int maxn = 2e5 + 10;
const double pi = acos(-1.0);
const ll mod = 1e9 + 7;

int n, m, t;
double p;

double qpow(double a, ll b)
{
    double res = 1;
    while(b) {
        if(b & 1) res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}

double f(double k)
{
    double ans = 0;
    double up = k * n + m;
    double down = 1 - qpow((1 - p), k);
    return up / down;
}

void solve()
{
    scanf("%d%d%lf", &n, &m, &p);
    p /= 10000.0;
    ll l = 1, r = 1e18;
    while(r - l > 2) {
        ll x = (2 * l + r) / 3;
        ll y = (2 * r + l) / 3;
        //cout << l << " " << r <<endl;
        if(f(x) < f(y) + eps) r = y;
        else l = x;
    }
    printf("%.10f\n", min({f(l), f(l + 1), f(l - 1), f(l + 2)}));
}
/*
3
1 1 5000
1 1 1
1 2 10000
*/
int main()
{
    scanf("%d", &t);
    while(t -- ) {
        solve();
    }
}

H、Harmonious Rectangle

Problem

定義 Harmonious Rectangle 為一個矩形記憶體在
{ color ( x 1 , y 1 ) = color ( x 1 , y 2 ) color ( x 2 , y 1 ) = color ( x 2 , y 2 ) 或 { color ( x 1 , y 1 ) = color ( x 2 , y 1 ) color ( x 1 , y 2 ) = color ( x 2 , y 2 ) \begin{cases} \text{color}(x_1, y_1) = \text{color}(x_1, y_2)\\ \text{color}(x_2, y_1) = \text{color}(x_2, y_2)\\\end{cases} \\或\\\begin{cases} \text{color}(x_1, y_1) = \text{color}(x_2, y_1)\\ \text{color}(x_1, y_2) = \text{color}(x_2, y_2)\\ \end{cases} {color(x1?,y1?)=color(x1?,y2?)color(x2?,y1?)=color(x2?,y2?)?{color(x1?,y1?)=color(x2?,y1?)color(x1?,y2?)=color(x2?,y2?)?

其中這四個點是矩形的端點, 問一個 n × m n\times m n×m 的矩陣,每個點可以涂 0 , 1 , 2 0,1,2 012 三種顏色,存在多少種矩陣是和諧矩陣,

n , m ≤ 3000 n,m\le 3000 n,m3000

Solution

憑感覺可知 n n n m m m 大于某個數后,一定全都含有和諧矩陣,(不然就沒法玩了 ,如果后面資料大,答案不是公式那將毫無意義 )即任意一種染色的方案都有貢獻,即答案就是染色總方案,每個格子有三種顏色可選,總方案為 3 n × m 3^{n\times m} 3n×m,然后爆搜找邊界就行了,

或者說使用抽屜原理,三種顏色,任意一組 ( a , b ) (a,b) (a,b) 每個都有三種選擇,一共有 3 × 3 = 9 3\times 3=9 3×3=9 種,根據抽屜原理,若 m a x { n , m } > 9 max\{n,m\}>9 max{n,m}>9 則無論怎么排列,都一定存在 和諧矩形,

可以在線搜索所有非法矩陣,列舉當前點是否可以放某個顏色的點,將爆搜優化到 3 n n 2 3^nn^2 3nn2,對 9 × 9 9 \times 9 9×9 以下的矩陣達打表輸出即可,

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
int res = 0;


int mat[9][9] = {{3,9,27,81,243,729,2187,6561},
                    {9,66,390,1800,6120,13680,15120,0},
                    {27,390,3198,13176,27000,13680,15120,0},
                    {81,1800,13176,24336,4320,0,0,0},
                    {243,6120,27000,4320,4320,0,0,0},
                    {729,13680,13680,0,0,0,0,0},
                    {2187,15120,15120,0,0,0,0,0},
                    {6561,0,0,0,0,0,0,0}};
void dfs(int cur,int n,int m)	//爆搜打表代碼
{
    if(cur == n * m){
        res++;
        return ;
    }
    for(int col = 0;col < 3;++col){
        int x = cur / m;
        int y = cur % m;
        bool flag = 1;
        for(int i = 0;i < x && flag;++i){
            for(int j = 0;j < y && flag;++j){
                if(mat[i][y] == mat[i][j] && mat[x][j] == col){
                    flag = 0;
                    break;
                }
                if(mat[i][y] == col && mat[i][j] == mat[x][j]){
                    flag = 0;
                    break;
                }
            }
        }
        mat[x][y] = col;
        if(flag)dfs(cur + 1, n, m);
    }
}

ll qpow(ll a, ll b)
{
    ll res = 1;
    while(b){
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

int main()
{
    int  t;
    cin>>t;
    while(t--){
        ll n,m;
        cin>>n>>m;
        if(n == 1 || m == 1) puts("0");
        else if(n < 9 && m < 9){
            printf("%lld\n",(qpow(3,n*m)-mat[n-1][m-1]+mod) % mod);
        }
        else{
            printf("%lld\n",qpow(3,n*m));
        }
    }
   return 0;
}

I、Interested in Skiing

Problem

二維平面 [ ? m , m ] × R [-m, m] \times \mathbb{R} [?m,m]×R 上有 n n n 條線段作為障礙,以端點坐標 ( x 1 , y 1 ) (x_1, y_1) (x1?,y1?) ( x 2 , y 2 ) (x_2, y_2) (x2?,y2?) 表示,起點為 ( 0 , ? inf ? ) (0, -\inf) (0,?inf) 的一個點以 v y v_y vy?的速度向 y \text{y} y 軸正方向移動,終點為 ( 0 , inf ? ) (0, \inf) (0,inf) ,求最小的 v x ? v_x^* vx??,使得當水平速度 v x > v x ? v_x \gt v_x^* vx?>vx?? 時,能從起點移動到終點,無解則輸出 ? 1 -1 ?1

1 ≤ n ≤ 100 , 1 ≤ m ≤ 1 0 4 , 1 ≤ v y ≤ 10 , ? m ≤ x 1 , x 2 ≤ m , ? 1 0 ? 4 ≤ y 1 , y 2 ≤ 1 0 4 1 \le n \le 100, 1 \le m \le 10^4, 1 \le v_y \le 10, -m \le x_1, x_2 \le m, -10^{-4} \le y_1, y_2 \le 10^4 1n100,1m104,1vy?10,?mx1?,x2?m,?10?4y1?,y2?104

J - Just Another Game of Stones

Problem

給定一個長度為 n n n 的陣列 a i a_i ai? ,有 q q q 次操作:

1 l r x 1~l~r~x 1 l r x ,表示令 a i = max ? { a i , x } , i ∈ [ l , r ] a_i = \max\{a_i, x\}, i \in [l, r] ai?=max{ai?,x},i[l,r]

2 l r x 2~l~r~x 2 l r x ,表示詢問用 [ l , r ] [l, r] [l,r] 的石堆和額外的一堆有 x x x 個石子的石堆一起,進行 Nim \text{Nim} Nim 博弈的必勝情況的第一步操作種數,

1 ≤ n , q ≤ 2 × 1 0 5 , 1 ≤ l , r ≤ n , 0 ≤ a i , x < 2 30 ? 1 1 \le n, q \le 2 \times 10^5, 1 \le l, r \le n, 0 \le a_i, x \lt 2^{30} - 1 1n,q2×105,1l,rn,0ai?,x<230?1

Solution

經典 Nim \text{Nim} Nim 博弈,若所有石子堆的石子數量的異或和為 0 0 0 則先手必敗,否則先手必勝,那么我們假設當前區間異或和為 S S S,顯然我們想要必勝,只需要取石子使得當前狀態變為必敗態送給對手,即在一堆里取石子,使得異或和變為 0 0 0 ,顯然有結論:對于一個石子數量為 a i a_i ai? 的石堆,取走 a i ? a i ⊕ S a_i - a_i \oplus S ai??ai?S 個石子,使得異或和 S S S 變為 0 0 0,也就是說若當前結點權值 a i a_i ai?,當 a i ≥ a i ⊕ S a_i\ge a_i \oplus S ai?ai?S ,則對該石子堆進行修改,即為一種合法的操作,故答案(總操作種數)即為區間里 a i ≥ a i ⊕ S a_i \ge a_i \oplus S ai?ai?S 的結點的數量,顯然異或是不進位的加法,即我們只需要考慮,對于當前區間的異或和 S S S S S S 的最高位 1 1 1,若 a i a_i ai? 在該最高位也是 1 1 1 ,則必有 a i ≥ a i ⊕ S a_i\ge a_i\oplus S ai?ai?S ,反之一定不成立,

這個題主要就是看會不會SGB,如果會的話就很簡單了,對于opt 1可以用SegmentTreeBeats的操作進行維護,對于opt 2可以考慮為線段樹的每個節點維護區間異或和,并開一個桶記錄每個位對應個數,向上合并的時候直接暴力合并就行了,總體復雜度 O ( n l o g n × 30 ) O(nlogn\times 30) O(nlogn×30)

記得考慮操作 2 加進來的石頭…

Code

 #include <bits/stdc++.h>
 
 using namespace std;
 using ll = long long ;
 const int maxn = 2e5+5;
 
 struct node
 {
 	ll mi;
 	ll smi;
 	ll xsum;
 	ll cntmi;
 	ll cnt[31];
 	ll tag;
 }tree[maxn*4];
 ll a[maxn];
 
 struct Segment_tree_beats
 {
 
 	void pushup(int rt){
 		if(tree[rt<<1].mi < tree[rt<<1|1].mi){
 			tree[rt].mi = tree[rt<<1].mi;
 			tree[rt].cntmi = tree[rt<<1].cntmi;
 			tree[rt].smi = min(tree[rt<<1].smi,tree[rt<<1|1].mi);
 			tree[rt].xsum = tree[rt<<1].xsum^tree[rt<<1|1].xsum;
 			for(int i = 0;i <= 30;++i)tree[rt].cnt[i] = tree[rt<<1].cnt[i]+tree[rt<<1|1].cnt[i];
 		}
 		else if(tree[rt<<1].mi > tree[rt<<1|1].mi){
 			tree[rt].mi = tree[rt<<1|1].mi;
 			tree[rt].cntmi = tree[rt<<1|1].cntmi;
 			tree[rt].smi = min(tree[rt<<1|1].smi,tree[rt<<1].mi);
 			tree[rt].xsum = tree[rt<<1|1].xsum^tree[rt<<1].xsum;
 			for(int i = 0;i <= 30;++i)tree[rt].cnt[i] = tree[rt<<1].cnt[i]+tree[rt<<1|1].cnt[i];
 		}
 		else{
 			tree[rt].mi = tree[rt<<1].mi;
 			tree[rt].cntmi = tree[rt<<1].cntmi+tree[rt<<1|1].cntmi;
 			tree[rt].smi = min(tree[rt<<1].smi,tree[rt<<1|1].smi);
 			tree[rt].xsum = tree[rt<<1].xsum^tree[rt<<1|1].xsum;
 			for(int i = 0;i <= 30;++i)tree[rt].cnt[i] = tree[rt<<1].cnt[i]+tree[rt<<1|1].cnt[i];
 		}
 	}
 
 	void pushtag(int rt,int val){
 		if(tree[rt].mi >= val)return;
 		if(tree[rt].cntmi&1){
 			tree[rt].xsum^=tree[rt].mi;
 			tree[rt].xsum^=val;
 		}
 		for(int i = 0;i <= 30;++i){
 			if(tree[rt].mi>>i&1)tree[rt].cnt[i]-=tree[rt].cntmi;
 			if(val>>i&1)tree[rt].cnt[i]+=tree[rt].cntmi;
 		}
 		tree[rt].mi = val;
 		tree[rt].tag = val;
 	}
 	void pushdown(int rt){
 		if(tree[rt].tag==-1)return;
 		pushtag(rt<<1,tree[rt].tag),pushtag(rt<<1|1,tree[rt].tag);
 		tree[rt].tag = -1;
 	}
 
 	void build(int rt,int l,int r){
 		tree[rt].tag = -1;
 		if(l==r){
 			tree[rt].mi = a[l];
 			tree[rt].xsum = a[l];
 			tree[rt].cntmi = 1;
 			tree[rt].smi = 1e18;
 			for(int j = 0;j <= 30;++j){
 				if(a[l]>>j&1)tree[rt].cnt[j]++;
 			}
 			return;
 		}
 		int mid = l+r>>1;
 		build(rt<<1,l,mid);
 		build(rt<<1|1,mid+1,r);
 		pushup(rt);
 	}
 
 	void modify_max(int rt,int l,int r,int ql,int qr,int val){
 		if(tree[rt].mi >= val)return;
 		if(l >= ql&& r<= qr&&tree[rt].smi > val){
 			pushtag(rt,val);
 			return;
 		}
 		pushdown(rt);
 		int mid = l+r>>1;
 		if(ql <= mid)modify_max(rt<<1,l,mid,ql,qr,val);
 		if(qr > mid)modify_max(rt<<1|1,mid+1,r,ql,qr,val);
 		pushup(rt);
 	}
 	int querysum(int rt,int l,int r,int ql,int qr){
 		if(l >= ql&& r <= qr){
 			return tree[rt].xsum;
 		}
 		pushdown(rt);
 		int mid = l+r>>1;
 		int sum = 0;
 		if(ql <= mid)sum^=querysum(rt<<1,l,mid,ql,qr);
 		if(qr > mid)sum^=querysum(rt<<1|1,mid+1,r,ql,qr);
 		return sum;
 	}
 	int querybit(int rt,int l,int r,int ql,int qr,int bit){
 		if(l >= ql&& r <= qr){
 			return tree[rt].cnt[bit];
 		}
 		pushdown(rt);
 		int mid = l+r>>1;
 		int sum = 0;
 		if(ql <= mid)sum+=querybit(rt<<1,l,mid,ql,qr,bit);
 		if(qr > mid)sum+=querybit(rt<<1|1,mid+1,r,ql,qr,bit);
 		return sum;
 	}
 }sgb;
 
 int main()
 {
 	int n,m;
 	scanf("%d%d",&n,&m);
 	for(int i = 1;i <= n;++i)scanf("%lld",&a[i]);
 	sgb.build(1,1,n);
 	while(m--){
 		int opt,l,r,val;
 		scanf("%d%d%d%d",&opt,&l,&r,&val);
 		if(opt==1){
 			sgb.modify_max(1,1,n,l,r,val);
 		}
 		else{
 			ll xsum = sgb.querysum(1,1,n,l,r);
 			xsum^=val;
 			int mx = -1;
 			for(int j = 30;j >= 0;--j){
 				if(xsum>>j&1){
 					mx = j;
 					break;
 				}
 			}
 			if(mx==-1)printf("0\n");
 			else{
 				printf("%d\n",sgb.querybit(1,1,n,l,r,mx)+(val>>mx&1));
 			}
 		}
 	}
 	return 0;
 }

K、K Co-prime Permutation

Problem

給定 n n n k k k ,構造一個排列 p i p_i pi? 使得 gcd ? ( p i , i ) = 1 \gcd(p_i, i) = 1 gcd(pi?,i)=1 i i i 的個數恰有 k k k 個,無解輸出 ? 1 -1 ?1

1 ≤ n ≤ 1 0 6 , 0 ≤ k ≤ n 1 \le n \le 10^6, 0 \le k \le n 1n106,0kn

Solution

顯然相鄰的兩個自然數互質,相鄰的兩個奇數互質,具體細節看代碼即可,

#include <bits/stdc++.h>
#define reg register
#define ios ios::sync_with_stdio(false)
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 2e5 + 10;
const double pi = acos(-1.0);
const ll mod = 1e9 + 7;

int n ,m, k;

int main()
{

    scanf("%d%d", &n, &k);
    if(k == 0) {
        puts("-1");
        return 0;
    }
    if(k == 1) {
        for(int i = 1; i <= n; ++ i)
        cout << i << " ";
        return 0;
    } 
    for(int i = 1; i < k; ++ i) {
        cout << i + 1 << " ";
    }
    cout << "1 ";
    for(int i = k + 1; i <= n; ++ i) {
        cout << i << " ";
    }
    puts("");
    return 0;
}

L、Let’s Play Curling

Problem

給定長度為 n n n 的陣列 a i a_i ai? 和長度為 m m m 的陣列 b i b_i bi?,對于一個數 c c c ,若 a i a_i ai?滿足對于所有 j j j ∣ c ? a i ∣ < ∣ c ? b j ∣ ∣ \vert c - a_i \vert \lt \vert c - b_j \vert∣ c?ai?<c?bj? 則得分加 1 1 1 ,最終得分 f ( c ) f(c) f(c) 為滿足的 i i i 的個數,求最大的 f ( c ) f(c) f(c)

Solution

顯然兩個 b b b 之間的數量最多的 a a a 的個數就是答案,

#include <bits/stdc++.h>
#define reg register
#define ios ios::sync_with_stdio(false)
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-10;
const int maxn = 2e5 + 10;
const double pi = acos(-1.0);
const ll mod = 1e9 + 7;

int a[maxn],b[maxn];

int main()
{
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
    ios;
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        for(int i = 1;i <= n;++i){
            cin>>a[i];
        }
        for(int i = 1;i <= m;++i){
            cin>>b[i];
        }
        b[0] = -inf;
        b[m + 1] = inf;
        sort(a+1,a+n+1);
        sort(b,b + m + 1);
        int res = 0;
        for(int i = 0;i <= m;++i){
            int l = upper_bound(a+1,a+n+1,b[i]) - a;
            int r = lower_bound(a+1,a+n+1,b[i+1]) - a - 1;
            res = max(r - l + 1, res);
        }
        if(!res) puts("Impossible");
        else printf("%d\n",res);
    }

    return 0;
}

M、Monster Hunter

樹上背包可以做到 O ( n 2 ) O(n^2) O(n2)

#include <bitsdc++.h>
using namespace std;

using ll = long long;
const int maxn = 2003;
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll dp[maxn][maxn][2];
int sz[maxn];
int a[maxn];
int n;
ll sum = 0;
vector<int>v[maxn];

void dfs(int now)
{
    sz[now] = 1;
    if(now!=1)sum += a[now]*2;
    else sum += a[now];
    dp[now][0][0] = 0;
    if(now!=1)
    dp[now][1][1] = 2*a[now];
    else dp[now][1][1] = a[now];
    dp[now][1][0] = -inf;
    dp[now][0][1] = -inf;
    if(v[now].size()==0){
        return;
    }
    for(int i = 0;i < v[now].size();++i){
        dfs(v[now][i]);
        for(int p = 0;p < 2;++p){
            for(int j = sz[now];j >= p;--j){
                for(int k = sz[v[now][i]];k >= 0;--k){
                    if(p==0){
                        dp[now][j+k][p] = max(dp[now][j+k][p],dp[now][j][p]+max(dp[v[now][i]][k][0],dp[v[now][i]][k][1]));
                    }
                    else{
                        long long tmp = dp[now][j][p]+dp[v[now][i]][k][0]+a[v[now][i]];
                        tmp = max(tmp,dp[now][j][p]+dp[v[now][i]][k][1]);
                        dp[now][j+k][p] = max(dp[now][j+k][p],tmp);
                    }
                }
            }
        }
        sz[now] += sz[v[now][i]];
    }
}

void solve()
{
    sum = 0;
    scanf("%d",&n);
    for(int i = 0;i <= n;++i){
        for(int j = 0;j <= n;++j)
        {
            for(int p = 0;p < 2;++p)dp[i][j][p] = -inf;
        }
    }
    for(int i = 1;i <= n;++i)v[i].clear();
    for(int i = 2,a;i <= n;++i){
        scanf("%d",&a);
        v[a].push_back(i);
    }
    for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
    dfs(1);
    for(int i = 0;i <= n;++i){
        printf("%lld%c",sum-max(dp[1][i][0],dp[1][i][1]),i==n?'\n':' ');
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        solve();
    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/273299.html

標籤:其他

上一篇:【筆記:模擬MOS集成電路】單級放大器(非高頻)

下一篇:2021ICPC昆明 M.Stone Games

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more