第 19 次 CCF CSP 認證(前三題)


TOP
目錄
\(202006-1\) 線性分類器
\(202006-2\) 稀疏向量
\(202006-3\) Markdown渲染器

$202006 - 1$ 線性分類器

img

img

img


\(AC\) 代碼:

#include<cstdio>
using namespace std;
const int N = 1000;
typedef long long LL;
struct point
{
    int x,y;
    char type;
}p[N];
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; ++i) {
        scanf("%d%d %c", &p[i].x, &p[i].y, &p[i].type);
    }
    for (int i = 0; i < m; ++i) {
        LL theta0, theta1, theta2;
        scanf("%lld%lld%lld", &theta0, &theta1, &theta2);
        bool flag = true;

        bool t = p[0].type == 'A' && theta0 + theta1 * p[0].x + theta2 * p[0].y > 0
            || p[0].type == 'B' && theta0 + theta1 * p[0].x + theta2 * p[0].y < 0;

        for (int j = 0; j < n; ++j) {

            flag = 
            t == (p[j].type == 'A' && theta0 + theta1 * p[j].x + theta2 * p[j].y > 0
            || p[j].type == 'B' && theta0 + theta1 * p[j].x + theta2 * p[j].y < 0);

            if (!flag) {
                puts("No");
                break;
            }
        }
        if (flag) puts("Yes");
    }
    return 0;
}

#if 0
    要點:利用 theta0 + theta1 * x + theta2 * y 的正負標記直線兩側。
    樣例1:
        9 3
        1 1 A
        1 0 A
        1 -1 A
        2 2 B
        2 3 B
        0 1 A
        3 1 B
        1 3 B
        2 0 A
        0 2 -3
        -3 0 2
        -3 1 1

#endif // 0

$202006-2$ 稀疏向量

img

img


題目就是求兩個 \(n\) 維向量的內積,並保證

\[\begin{cases} n\le10^9 \\ 0\lt a,b\le 5\times 10^5 \\|u_i|,|v_i|\le10^6 \end{cases} \]

估算出結果最大為 \(\sum_{i=1}^{5\times 10^5} 10^6\times 10^6=5\times 10^{17}\) ,而 \(max(long\text{ }long)\gt 9.2\times 10^{18}\) ,故結果可用 \(long\text{ }long\) 裝下。

然后很容易想到,將輸入數據根據維度排序或者用 \(map\) 映射,時間復雜度最多不過 \(O((a+b)\,\log\,(a+b))\) ,之后進行累乘只需線性復雜度。

\(AC\) 代碼:

#include<cstdio>
#include<map>
using namespace std;
map<int, int> mp;
long long ans = 0;
int main()
{
    int n, a, b;
    scanf("%d%d%d", &n, &a, &b);

    int index, value;
    for (int i = 0; i < a; ++i) {
        scanf("%d%d", &index, &value);
        mp[index] = value;
    }

    map<int, int>::iterator it; // 一定要定義在循環體外!
    for (int i = 0; i < b; ++i) {
        scanf("%d%d", &index, &value);
        it = mp.find(index);
        if (it == mp.end()) continue;
        ans += 1LL * value * it->second;
    }
    printf("%lld", ans);
    return 0;
}

#if 0
    樣例輸入:
        10 3 4
        4 5
        7 -3
        10 1
        1 10
        4 20
        5 30
        7 40

#endif // 0

\(17\) 行的迭代器我第一次定義在函數體內,結果運行超時,真是被自己玩死了。

$202006-3$ Markdown渲染器

img

img

img

img

img


不愧是第 \(3\) 題,出場總是如此霸氣,一個題硬生生就占了 \(5\) 頁,整個第 \(19\) 次認證的 \(1/3\)

硬着頭皮讀完題目,發現其實並沒有那么可怕,不就是一個渲染段落和項目列表的模擬嘛,要是我考試的時候也能這么說就好了

思路

  • 統計渲染后的字符數 tot (空行計為 \(w\) 個字符,中間不滿 \(w\) 個字符的行需填充),最后向上整除屏幕寬度得到行數 (tot + w - 1) / w

  • 輸入數據不超過 \(20MB\),即 \(20971520B\) ,可以考慮用 getchar() 讀取。

  • 變量 stat 記錄上一行狀態: 空行段落項目 。初始化為 空行
  • 若當前行為 空行
    • 若上一行不為 空行 ,則填充上一行 tot = (tot + w - 1) / w * w
    • 否則不處理
  • 若當前行為 "* " 開頭的 項目
    • 填充上一行並在新的一行添加三個字符 tot = (tot + w - 1) / w * w + 3
    • 若上一行為 段落 則增加一個空行
    • 從除行首的 '*' 以外的第一個非空字符開始按照 普通段落 處理。
  • 若當前行為 " " 開頭的 項目
    • 若上一行字符數多於 \(3\) 個且未滿一行,則增加一個空格
    • 從第一個非空字符開始按照 普通段落 處理,注意每次換到新的一行需先增加 \(3\) 個字符(空格)
  • 若當前行為 段落
    • 若上一行為 項目 ,則填充上一行並增加一個空行 tot = (tot + w - 1) / w * w + w
    • 若上一行為 段落 且字符數未滿一行,則增加一個空格。
    • 從第一個非空字符開始按照 普通段落 處理

\(AC\) 代碼:

#include<cstdio>

enum{paragraph, space, item = 3} stat = space;
char c;
int w;
long long tot = 0;

char aLine()
{
    int cnt = 0;
    while((c = getchar()) == ' ') ++cnt;
    if (c == '\n' || c == EOF) {
        /*當前行為空行*/

        if (stat != space) {
            tot = (tot + w - 1) / w * w;
            stat = space;
            tot += w;
        }
        return c;
    }

    if (cnt == 0 && c == '*') {
        c = getchar();
        if (c == ' ') {
            /*當前行為項目*/
            tot = (tot + w - 1) / w * w + 3;
            if (stat == paragraph) tot += w;
            while ((c = getchar()) == ' ');
            stat = item;
        }
        else {
            /*當前行為段落*/
            if (stat == item) {
                tot = (tot + w - 1) / w * w + w;
            }
            else if (tot % w) ++tot;
            tot += 1;
            stat = paragraph;
        }
    }
    else if (cnt >= 2 && stat == item) {
        /*當前行為項目*/
        if (tot % w > 3) ++tot;
    }
    else {
        /*當前行為段落*/
        if (stat == item) {
            tot = (tot + w - 1) / w * w + w;
        }
        else if (tot % w) ++tot;
        stat = paragraph;
    }


    cnt = 0;
    /*非空行剩余字符*/
    while (c != '\n' && c != EOF) {
        if (c != ' ') {
            if (tot % w == 0) tot += stat;
            ++tot;
            cnt = 0;
        }
        else if (tot % w) {
            ++tot;
            ++cnt;
        }
        c = getchar();
    }
    tot -= cnt;
    return c;
}

int main()
{
    scanf("%d", &w);

    while((c = getchar()) != '\n' && c != EOF);

    while(~aLine()); // 一行行處理
    if (stat == space && tot > w) tot -= w;

    printf("%lld", (tot + w - 1) / w);
    return 0;
}

#if 0
樣例1:
10
CSP

CSP is
a real realrealrealrealreal
     competition.


Come   and   join   us



樣例2:
10
* CSP

*   CSP is
  * a real
     competition.
*
  * Come!   and   join.
*Tel:
* 12345
*

#endif // 0

像這種大模擬還是得細心吶!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM