24牛客多校第一場

zouyua發表於2024-07-17

牛客多校第一場

按過題人數順序

C.Sum of Suffix Sums

  • 題意: 定義 $suf_i = \sum_i^n a_i $
  • q個操作每次給出 t, v 代表每次從序列中刪除後面t個後,加入一個v, 每次操作後輸出 $\sum_1^{size} suf_i $

簽到題,因為初始為空,且不會刪除空序列,每次只加入一個數,模擬時間複雜度為O (q), 關鍵在於取模

int main()
{
	int q; cin >> q;
    vector<ll> a;
    ll res = 0;
    while(q --) {
        ll t, v; cin >> t >> v;
        while(t --) {
            ll tmp = 1ll * a.size() * a.back() % mod;
            res = (res - tmp % mod + mod) % mod;
            a.pop_back();
        }
        a.push_back(v);
        ll tmp = 1ll * a.size() * a.back() % mod;
        res = (res + tmp) % mod;       
        cout << res << endl;
    }
    
	return 0;
}

H.World Finals

  • 題意:兩場比賽都給出了每場的參賽隊伍名稱,過題數,罰時,如果同一個參賽隊伍這兩場比賽全參加了那麼可以任意分配兩場都參加了的隊伍的比賽場次的選擇,問lzr010506最高可能的排名是多少?

也是簽到題,分別計算出每場lzr010506在只參加某一場的隊伍中的排名,因為參加兩場的可以隨便選擇,取min就是答案

struct Info {
    string s;
    int t, f;
    bool operator < (const Info& _) const {
        if(t == _.t) return f < _.f;
        return t > _.t;
    }
};
int main()
{
	int n, m; cin >> n;
    map<string, int> mp1, mp2;
    vector<Info> comp1(n);
    for(auto &[s, t, f] : comp1) {
        cin >> s >> t >> f;
        mp1[s] ++;
    }
    cin >> m;
    vector<Info> comp2(m);
    for(auto &[s, t, f] : comp2) {
        cin >> s >> t >> f;
        mp2[s] ++;
    }
    sort(comp1.begin(), comp1.end());
    sort(comp2.begin(), comp2.end());
    int rk1 = 1, rk2 = 1;
    for(auto &[s, t, f] : comp1) {
        if(s == "lzr010506") break;
        if(mp2.find(s) == mp2.end()) rk1 ++;
    }
    for(auto &[s, t, f] : comp2) {
        if(s == "lzr010506") break;
        if(mp1.find(s) == mp1.end()) rk2 ++;
    }
    cout << min(rk1, rk2) << endl;
	return 0;
}

A.A Bit Common

  • 題意:求有多少長為 n 的元素是 [0, $ 2^m $) 的整數序列滿足存在一個非空子序列的 AND 和是 1 答案對輸入的正整數 q 取模
  • 1 ≤ n, m ≤ 5000, 1 ≤ q ≤ $10^9$

資料範圍提示應該是個$n^2$的做法或者$n*m$,


I.Mirror Maze

  • 題意:有一個 n × m 的矩形鏡子迷宮,鏡子有 “\, /, -, |” 四種,每種鏡子有特定的光線反射方向,注意直接透過鏡子的情況不算被反射。
  • 有 q 個詢問,每個詢問給定一個點光源 (x, y, dir),表示在 (x, y) 位置向dir 方向發射一束光線,問經過足夠的時間之後,這束光線被多少個不
    同的鏡子反射過。
  • $ 1 ≤ n, m ≤ 1000, 1 ≤ q ≤ 10^5 $

賽時當模擬寫的,剛開始想的圖論,發現建圖能力不夠,後來轉向記憶化,能造的樣例都能過,賽後只過了6%,還是存在大問題

因為是鏡子,所以可以一直反射,如果不出界,最終會形成一個環,否則會形成一個鏈到外界。逆著看,就是從外面射進來得一束光,預處理最外層射進來的每一束光,處理完剩下的點一定在某個環中,再處理這個所在的環。所有處理過的點都標記一下,防止多次遍歷,點在insert前要判斷會不會被反射回來

用set維護鏈。用一個陣列存下來路徑,能避免傳參過多導致記憶化不好處理的麻煩,更新答案因為是記憶化歸的過程,要逆著邊更新邊處理

同樣用set也可以維護環,但是歸的過程要把路徑上的所有點更新,即先處理完資料再更新答案

struct node {
    int x, y, d;
    node(int x, int y, int d) : x(x), y(y), d(d) {}
};
char g[N][N];
map<string, int> mp;
int st[N][N][4], res[N][N][4];
int n, m, q;
vector<node> pt;
bool ref(int x, int y, int dir) {
    char c = g[x][y];
    if(c == '\\' || c == '/') return true;
    if(c == '-' && dir <= 1) return true;
    if(c == '|' && dir >= 2) return true;
    return false;
}
void dfs(int x, int y, int dir) {
    if(x < 1 || x > n || y < 1 || y > m) return ;
    if(st[x][y][dir]) return ;
    st[x][y][dir] = 1;
    pt.push_back((node){x, y, dir});
    char c = g[x][y];
    if(c == '-') {
        if(dir == 0) dfs(x + 1, y, 1);
        else if(dir == 1) dfs(x - 1, y, 0);
        else if(dir == 2) dfs(x, y -1, 2);
        else dfs(x, y + 1, 3);
    } else if(c == '|') {
        if(dir == 0) dfs(x - 1, y, 0);
        else if(dir == 1) dfs(x + 1, y, 1);
        else if(dir == 2) dfs(x, y + 1, 3);
        else dfs(x, y - 1, 2);
    } else if(c == '\\') {
        if(dir == 0) dfs(x, y - 1, 2);
        else if(dir == 1) dfs(x, y + 1, 3);
        else if(dir == 2) dfs(x - 1, y, 0);
        else dfs(x + 1, y, 1);
    } else if(c == '/') {
        if(dir == 0) dfs(x, y + 1, 3);
        else if(dir == 1) dfs(x, y - 1, 2);
        else if(dir == 2) dfs(x + 1, y, 1);
        else dfs(x - 1, y, 0);
    }
}
void solve1(int x, int y, int dir) {//處理鏈,倒序判斷,避免傳參導致資訊不好維護
    pt.clear();
    dfs(x, y, dir);
    reverse(pt.begin(), pt.end());
    set<PII> s;
    for(auto &[x, y, d] : pt) {
        if(ref(x, y, d)) {
            s.insert({x, y});
        }
        res[x][y][d] = s.size();
    }
}
void solve2(int x, int y, int dir) {//處理環, 環是迴圈,上面每個方向的2點的答案都一樣
    pt.clear();
    dfs(x, y, dir);
    reverse(pt.begin(), pt.end());
    set<PII> s;
    for(auto &[x, y, d] : pt) {
        if(ref(x, y, d)) {
            s.insert({x, y});
        }
    }
    for(auto &[x, y, d] : pt) {
        res[x][y][d] = s.size();
    }
}
int main()
{
	cin >> n >> m;
    for(int i = 1; i <= n ;i ++) {
        cin >> g[i] + 1;
    }
    for(int i = 1; i <= n; i ++) {
        solve1(i, 1, 3);
        solve1(i, m, 2);
    }
    for(int j = 1; j <= m; j ++) {
        solve1(1, j, 1);
        solve1(n, j, 0);
    }
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            for(int k = 0; k < 4; k ++) {
                if(!st[i][j][k]) {
                    solve2(i, j, k);
                }
            }
        }
    }
    mp["above"] = 0;
    mp["below"] = 1;
    mp["left"] = 2;
    mp["right"] = 3;
    cin >> q;
    while(q --) {
        int x, y; string s; cin >> x >> y >> s;
        int tmp = mp[s];
        if(tmp == 0) x--;
        else if(tmp == 1) x ++;
        else if(tmp == 2) y --;
        else y ++;
        cout << res[x][y][tmp] << endl;
    }
	return 0;
}

相關文章