日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Contest3376 - 2024寒假集训-排位赛竞赛(一)

發布時間:2024/1/21 windows 46 coder
生活随笔 收集整理的這篇文章主要介紹了 Contest3376 - 2024寒假集训-排位赛竞赛(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

A: 冪位和

高精度

用高精度加法或乘法算出\(2^{1000}\),再將各位累加即為答案。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

string AP_add(string A, string B) // 高精度加法
{
    int lena = A.size(), lenb = B.size(), lenc = max(lena, lenb) + 1;
    reverse(A.begin(), A.end()); reverse(B.begin(), B.end());
    vector<int> a(lenc), b(lenc), c(lenc);
    for (int i = 0; i < lena; i++) a[i] = A[i] - '0';
    for (int i = 0; i < lenb; i++) b[i] = B[i] - '0';
    int x = 0;
    for (int i = 0; i < lenc; i++)
    {
        c[i] = a[i] + b[i] + x;
        x = c[i] / 10;
        c[i] %= 10;
    }
    while (c.back() == 0 && c.size() > 1) c.pop_back();
    string C = "";
    for (auto i : c) C += i + '0';
    reverse(C.begin(), C.end());
    return C;
}

int main()
{
	cctie;
	
	string s = "1";
	for (int i = 1; i <= 1000; i++) s = AP_add(s, s);

	int ans = 0;
	for (auto i : s) ans += i - '0'; // 各位累加
	cout << ans << '\n';

	return 0;
}

B: 三角形數

質因數分解/試除法

對某數質因數分解后,將各個次冪累乘即為該數的約數個數(試除法也行,較慢一些),按要求循環直到找到約數個數大于\(500\)的數即可。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

int get(int n) // 求n的約數個數
{
    int ans = 1;
    for (int i = 2; i <= n / i; i++)
    {
        int cnt = 0;
        while (n % i == 0)
            n /= i, cnt++;
        ans *= cnt + 1;
    }
    if (n > 1) ans *= 2;
    return ans;
}

int main()
{
	cctie;
    
    int k = 1;
	for (int i = 1; ; i += ++k)
    {
        if (get(i) > 500) // 找到目標數
        {
            cout << i << '\n';
            break;
        }
    }

	return 0;
}

C: 生日蛋糕

搜索、剪枝、后綴和

所求表面積即為第一層蛋糕的下表面積(相當于每一層蛋糕上表面外露面積之和)與每層蛋糕的側面積之和。

主要對\(dfs\)中的四個剪枝分析。

  1. \(V<minV[u]\)。剩余體積不足以按要求設計出第\(u\)層及以上的蛋糕。

  2. \(S + minS[u] >= ans\)。即使能夠按要求設計出剩余層數的蛋糕但也無法更新答案。

  3. \(S + 2 * \frac{V}{R[u - 1]} >= ans\)。最重要的剪枝,推導如下(忽略所有\(\pi\))。

    記第\(1\)層到第\(u-1\)層的側面積和第一層的下表面積為\(S\),第\(u\)層到第\(m\)層的側面積為\(S'=\sum_{i=u}^{m}2R_iH_i=\frac{2}{R_{u-1}}\sum_{i=u}^{m}R_{u-1}R_iH_i\)

    \(R_{u-1}>R_{u}>R_{u+1}>...>R_m\)\(S'>=\frac{2}{R_{u-1}}\sum_{i=u}^{m}R_i^2H_i\)(當且僅當\(u=m+1\)時取得等號);

    \(V=\sum_{i=u}^{m}R_i^2H_i\)\(S'\geq\frac{2}{R_{u-1}}V\)

    \(S+S'>=S + 2 * \frac{V}{R[u - 1]}>=ans\)時無法更新答案(道理同\(2\))。

  4. \(for\)循環中\(r\)\(h\)的取值范圍。由每一層的\(r\)\(h\)都是正整數且都比上一層的\(r\)\(h\)的大得到下界,由第\(u\)層的體積最大值\(V-minV[u+1]\)和該層的高的最小值確定\(r\)的上界,\(h\)的值隨\(r\)而確定。

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

const int N = 30, INF = 0x3f3f3f3f; // INF表示一個極大的值(本題答案無法達到,用于判斷是否有答案)

int n, m;
int minV[N], minS[N]; // minV[i]、minS[i]分別表示第i層及以上部分構成的最小體積、表面積
int R[N], H[N]; // R[i]、H[i]表示當前第i層蛋糕的半徑和高度
int ans = INF; 

void dfs(int u, int V, int S) // 搜索,表示考慮第u層蛋糕,剩余體積為V,已有蛋糕的表面積為S
{
    if (V < minV[u]) return;
    if (S + minS[u] >= ans) return;
    if (S + 2 * V / R[u - 1] >= ans) return;
    if (u == m + 1) // 搜索完m層蛋糕
    {
        if (V == 0) ans = S; // 更新答案
        return;
    }
    // 從大到小,先遍歷r,后遍歷h
    for (int r = min(R[u - 1] - 1, (int)sqrt((V - minV[u + 1]) / (m + 1 - u))); r >= m + 1 - u; r--) 
        for (int h = min(H[u - 1] - 1, (V - minV[u + 1]) / (r * r)); h >= m + 1 - u; h--)
        {
            R[u] = r, H[u] = h;
            dfs(u + 1, V - r * r * h, S + 2 * r * h + (u == 1) * r * r); // 第一層有額外的下表面積
        }
}

int main()
{
	cctie;
	
	cin >> n >> m;
    R[0] = H[0] = INF; // dfs中第三行if需要
    for (int i = m; i >= 1; i--) // 求后綴和
    {
        int j = m + 1 - i;
        minV[i] = minV[i + 1] + j * j * j;
        minS[i] = minS[i + 1] + 2 * j * j;
    }

    dfs(1, n, 0);

    if (ans == INF) ans = 0; // 沒有搜索到可行解
    cout << ans << '\n';

	return 0;
}

D: 頭疼的數列

動態規劃

\(dp[i][j]\)表示使序列的前\(i\)個數都變成\(j\)所需要的最少操作數,\(1\leq i\leq n\)\(0\leq j \leq 1\)

狀態轉移方程如下:

\(a[i]=1\),則\(dp[i][1]=\min(dp[i-1][1],dp[i-1][0]+1),dp[i][0]=\min(dp[i-1][0],dp[i-1][1])+1\)

\(a[i]=0\),則\(dp[i][0]=\min(dp[i-1][0],dp[i-1][1]+1),dp[i][1]=\min(dp[i-1][1],dp[i-1][0])+1\)

用異或運算\(\oplus\)可以合二為一,如下:

\(dp[i][a[i]] = min(dp[i - 1][a[i]],dp[i - 1][a[i]\oplus 1] + 1),dp[i][a[i] \oplus 1] = min(dp[i - 1][a[i] \oplus 1],dp[i - 1][a[i]]) + 1\)

答案即為\(dp[n][0]\)

時間復雜度:\(O(n)\)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)

const int N = 100010, INF = 0x3f3f3f3f;

int n;
int a[N];
int dp[N][2];

int main()
{
	cctie;
	
	cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    dp[1][a[1]] = 0, dp[1][a[1] ^ 1] = 1;
    for (int i = 2; i <= n; i++)
    {
        dp[i][a[i]] = min(dp[i - 1][a[i]], dp[i - 1][a[i] ^ 1] + 1);
        dp[i][a[i] ^ 1] = min(dp[i - 1][a[i] ^ 1], dp[i - 1][a[i]]) + 1;
    }
    cout << dp[n][0] << '\n';

	return 0;
}

E: 楊輝三角

模擬

按題目要求即\(a[i][j]= a[i - 1][j - 1] + a[i - 1][j]\)構造出楊輝三角,再按題目要求的格式輸出即可。

#include <bits/stdc++.h>
 
using namespace std;
 
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define i64 long long 
#define double long double 
#define PII pair<int, int>
 
const int N = 1010;
 
int n;
int a[N][N];
 
int get(int x) // 求x的寬度
{
    int cnt = 0;
    while (x) cnt++, x /= 10;
    return cnt;
}
 
void solve()
{
    int mx = 0; // 最大值
    for (int j = 1; j <= n; j++)
        mx = max(mx, a[n][j]);
    int cnt = get(mx); // 最大數的寬度
    for (int i = 1; i <= n; i++)
    {
        cout << a[i][1];
        for (int j = 2; j <= i; j++)
            cout << setw(cnt + 1) << a[i][j]; // 按要求格式輸出
        cout << '\n';
    }
    cout << '\n';
}
 
int main()
{
    cctie;
    a[1][1] = 1;
    for (int i = 2; i <= 30; i++)
        for (int j = 1; j <= i; j++)
            a[i][j] = a[i - 1][j - 1] + a[i - 1][j];
    while (cin >> n) solve();
 
    return 0;
}

F: 頭疼的花匠

樹狀數組/線段樹、離散化、排序、離線詢問

對每朵花和詢問的點的坐標按x的大小分別排序(升序),我們依次求排序后的每個詢問,不妨設當前處理的詢問的點的橫坐標為\(x\),縱坐標為\(y\),則只需要求所有橫坐標不大于\(x\)的花中縱坐標不大于\(y\)的有幾朵,此處需要借助樹狀數組或線段樹實現單點修改和區間查詢,我們遍歷排序后的每朵花,只要當前花的橫坐標不大于x,就在樹狀數組中標記該花的縱坐標出現次數加一,而對于之前處理詢問過程中已經標記過的點不需要重復遍歷。這樣處理每朵花只會被標記一次,每個詢問處理也只有一次區間查詢。

時間復雜度:\(O((n + q)log(n+q))\)

#include <bits/stdc++.h>
 
using namespace std;
 
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define PII pair<int, int>
 
const int N = 100010, INF = 0x3f3f3f3f, mod = 998244353;

template <typename T>
class Fenwick // 樹狀數組
{
private:
    int n;
    vector<T> c;
    int lowbit(int x) 
    {
        return x & -x;
    }
public:
    Fenwick(int n) : n(n - 1), c(n) {}
    
    void add(int k, T x) // 單點修改
    {
        for (int i = k; i <= n; i += lowbit(i)) c[i] += x;
    }
    
    T sum(int k) // 區間查詢
    {
        T sum = T();
        for (int i = k; i; i -= lowbit(i)) sum += c[i];
        return sum;
    }
};

int n, q;
PII a[N], b[N];
int order[N];
int ans[N];

int main()
{
    cctie;
    
    cin >> n >> q;
    vector<int> v(1);
    for (int i = 1; i <= n; i++)
    {
        int x, y; cin >> x >> y;
        a[i] = {x, y};
        v.push_back(y);
    }
    for (int i = 1; i <= q; i++)
    {
        int x, y; cin >> x >> y;
        b[i] = {x, y};
        v.push_back(y);
    }

    sort(v.begin() + 1, v.end());
    v.erase(unique(v.begin() + 1, v.end()), v.end()); // 離散化

    sort(a + 1, a + n + 1);
    iota(order + 1, order + q + 1, 1);
    sort(order + 1, order + q + 1, [&](int i, int j)
    {return b[i] < b[j];});

    auto get = [&](int x)->int
    {
        return lower_bound(v.begin() + 1, v.end(), x) - v.begin();
    }; // 求離散化后的值

    Fenwick<int> F(v.size());
    int now = 1;
    for (int i = 1; i <= q; i++)
    {
        int j = order[i];
        while (now <= n && a[now].first <= b[j].first) F.add(get(a[now++].second), 1); // 標記縱坐標
        ans[j] = F.sum(get(b[j].second)); // 處理詢問
    }

    for (int i = 1; i <= q; i++) cout << ans[i] << '\n';

    return 0;
}

G: 貨倉選址

數學

經典數學問題,貨倉建在中位數即可。

時間復雜度:\(O(nlogn)\)

#include <bits/stdc++.h>

using namespace std;

#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define i64 long long
 
const int N = 100010, INF = 0x3f3f3f3f;

int n;
int a[N];

int main()
{
    cctie;
    
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + n + 1);
    int k = n + 1 >> 1; // 求中位數下標
    i64 ans = 0;
    for (int i = 1; i <= n; i++) ans += abs(a[i] - a[k]);
    
    cout << ans << '\n';
    
    return 0;
}

H: 進階楊輝三角

模擬

其實就是將\(E\)題里的楊輝三角按順序存放到一維數組里,然后求第\(k\)個數直接輸出即可,注意取模。

#include <bits/stdc++.h>
 
using namespace std;
 
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define i64 long long 
 
const int N = 1010, mod = 1e9 + 7;
 
i64 a[N][N];
vector<i64> v(2, 1);
 
void solve()
{
    int k; cin >> k;
    cout << v[k] << '\n';
}
 
int main()
{
    cctie;
    a[1][1] = 1;
    for (int i = 2; ; i++)
    {
        if (v.size() - 1 >= 50000) break;
        for (int j = 1; j <= i; j++)
        {
            if (v.size() - 1 >= 50000) break;
            a[i][j] = (a[i - 1][j - 1] + a[i - 1][j]) % mod;
            v.push_back(a[i][j]); // 存放到一維數組
        }
    }
    int t; cin >> t;
    while (t--) solve();
 
    return 0;
}

I: 切面條

找規律

將面條兩端相接則成環(視為已對折一次),則一共對折\(n(n>0)\)次后切割能得到\(2^n\)根面條,而面條相較于環多了個開口,也就是切割后多了一根面條,所以答案為\(2^n+1\)

#include <bits/stdc++.h>
 
using namespace std;
 
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
 
int n;
 
int main()
{
    cctie;
    cin >> n;
 
    cout << (1 << n) + 1 << '\n';
 
    return 0;
}

J: 進制轉換

進制轉換

\(p\)進制數轉\(q\)進制:先將\(p\)進制數轉為十進制數,再將十進制數轉為\(q\)進制數。

轉換原理和過程略。

#include <bits/stdc++.h>
 
using namespace std;
 
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
 
int p, q;
string n;
 
string itoa1(int n, int m) // 十進制數n轉m進制
{
    string ret = "";
    do
    {
        int t = n % m;
        if (0 <= t && t <= 9) ret += t + '0';
        else ret += t - 10 + 'A';
        n /= m;
    } 
    while(n);
    reverse(ret.begin(), ret.end());
    return ret;
}
 
int itoa2(string n, int m) // m進制數n轉十進制
{
    int ret = 0, k = 1;
    while (n != "")
    {
        char c = n.back();
        n.pop_back();
        if (c >= 'A') ret += (c - 'A' + 10) * k;
        else ret += (c - '0') * k;
        k *= m;
    }
    return ret;
}
 
int main()
{
    cctie;
 
    cin >> p >> q >> n;
    cout << itoa1(itoa2(n, p), q) << '\n';
 
    return 0;
}

K: 超級楊輝三角

組合數學、乘法逆元

題目要求所有滿足條件\(\exists \{i,j\}, a_{i-1}<a_i,a_{j-1}>a_j\)的長度為\(n\)且每個數不大于\(k\)的序列個數\(C\)。直接求很困難,不妨先求其對立部分的序列個數記為\(B\),再用長度為\(n\)且每個數不大于\(k\)的序列個數\(A\)減去\(B\)即為答案。顯然與前面條件對立的序列即為單調序列(非嚴格),轉而求長度為\(n\)且每個數不大于\(k\)的單調序列個數。

先求單調上升的序列個數。把序列的\(n\)個位置當作\(n\)個球,從\(1\)\(k\)\(k\)個數當作\(k\)個盒子(按升序擺放),則求單調上升的序列個數及等效于把\(n\)個球放到\(k\)個盒子里的放法個數(可以有空盒),這是經典組合數學問題。先手動將每個盒子放一個球,則問題轉變為把\(n+k\)個球放到\(k\)個盒子里的放法個數(不能有空盒),用隔板法解決,在\(n+k-1\)個間隙里放\(k-1\)個隔板,答案即為\(C_{n+k-1}^{k-1}\)

單調下降的序列個數顯然同樣也為\(C_{n+k-1}^{k-1}\),由于與單調上升序列有所重合,重合部分為n個數相等的所有序列,一共\(k\)個。

\(B=2C_{n+k-1}^{k-1}-k\),再求\(A\),顯然\(A=k^n\),則\(C=A-B=k^n -(2C_{n+k-1}^{k-1}-k)\)

時間復雜度:\(O(\min(n, k))\)

#include <bits/stdc++.h>
 
using namespace std;
 
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define i64 long long
 
const int mod = 998244353;

i64 pow(i64 a, i64 b, i64 p = mod) // 快速冪
{
	i64 ans = 1 % p;
	while (b)
	{
		if (b & 1) ans = ans * a % p;
		b >>= 1;
		a = a * a % p;
	}
	return ans;
}

i64 C(i64 a, i64 b, i64 p = mod) // 求組合數
{
    if (b > a) return 0;
    if (b > a - b) b = a - b;
    i64 x = 1, y = 1;
    for (int i = 0; i < b; i++)
    {
        x = x * (a - i) % p;
        y = y * (b - i) % p;
    }
    return x * pow(y, p - 2) % p;
}

void solve()
{
    i64 n, k; cin >> n >> k;
    i64 ans = (pow(k, n) - ((2 * C(n + k - 1, k - 1) - k + mod) % mod) + mod) % mod;
    cout << ans << '\n';
}

int main()
{
    cctie;
    
    int t; cin >> t;
    while (t--) solve();

    return 0;
}

L: 數列的平方和

前綴和/尺取法

本題要求出所有長度為\(m\)的區間和(每個數平方后)的最小值。

這里主要講一下尺取法的寫法,類似滑動窗口的思路,我們從左往右求每一個區間的和,\(i\)表示當前所維護區間的最右端,則當前需要維護的區間和為\(\sum_{j=i-m+1}^{i}\),而上一個區間的和為\(\sum_{j=i-m}^{i-1}=now\),可以得出當前區間的和為\(now-a[i-m]+a[i]\),一直維護取最小值即可。

時間復雜度:\(O(n)\)

#include <bits/stdc++.h>
 
using namespace std;
 
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define i64 long long 
 
const int N = 100010, mod = 1e9 + 7;
 
int n, m;
int a[N];
 
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++) 
    {
        cin >> a[i];
        a[i] *= a[i];
    }
    i64 ans = LLONG_MAX, now = 0;
    for (int i = 1; i <= n; i++)
    {
        now += a[i];
        if (i > m) now -= a[i - m];
        if (i >= m) ans = min(ans, now);
    }
    cout << ans << '\n';
}
 
int main()
{
    cctie;
 
    int T; cin >> T;
    while (T--) solve();
 
    return 0;
}

總結

以上是生活随笔為你收集整理的Contest3376 - 2024寒假集训-排位赛竞赛(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。