1. 程式人生 > >csu-2018年11月月賽Round2-div1題解

csu-2018年11月月賽Round2-div1題解

ons 出現 表示 否則 -c 才有 ... for mat

csu-2018年11月月賽Round2-div1題解

A(2191):Wells的積木遊戲

Description

Wells有一堆N個積木,標號1~N,每個標號只出現一次 由於Wells是手殘黨,所以每次只能取出一塊積木放在積木頂層 現在Wells想知道至少需要操作幾次可以把積木堆成從頂至底標號升序 不論什麽都很菜的Wells顯然不知道怎麽做 所以作為人生贏家的你義不容辭的決定幫助可憐的Wells

Input

第一行一個正整數N
接下來N行,從頂至底描述每塊積木的標號

Output

輸出一行,為最小操作次數

Sample Input

3
3
2
1

Sample Output

2

Hint

樣例數據的兩次操作(3,2,1)->(2,3,1)->(1,2,3) N<=10^5


題解:

div-1難得的水題,找幾個數據看一下就可以發現從最大積木的開始向前找,連續的是有貢獻的,比如

2 1 5 3 4 6, 6之前只有5這一個連續數字,所以貢獻為2,答案就為6 - 2 = 4

代碼:

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int a[maxn];
int main() {
    int n;
    scanf("%d", &n);
    int maxx = 0, maxpos;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        if (a[i] > maxx) {
            maxx = a[i];
            maxpos = i;
        }
    }
    int cnt = 1;
    for (int i = maxpos - 1; i >= 1; i--) {
        if (a[i] == maxx - 1) {
            cnt++;
            maxx -= 1;
        }
    }
    cout << n - cnt;
    return 0;
}

B(2192):Wells彈鍵盤

Description

Wells十分羨慕和佩服那些會彈鋼琴的人比如子浩君,然而Wells只會彈鍵盤…… Wells的鍵盤只有10個鍵,從1,2,3,……,9,0,如下圖所示:

而且作為一個正常人,Wells也有兩只手,但是為了顯示出自己高超的彈鍵盤水平,Wells決定每只手只動用一個手指,左手指和右手指,來進行按鍵操作,初始左右手指分別在5,6兩個按鍵上。每一個單位時間(1s),對於一個手指,Wells可以進行如下操作之一:

  • 按下位於手指位置的按鍵。
  • 將手指向左或向右移動一格,當然不能移到鍵盤外面。

必須註意以下幾點:

  • 在任意時刻,正常人左手指都必須在右手指的左邊,當然右手指就在左手指的右邊。
  • 在一個單位時間內,只有一個手指可以按下按鍵。當然,另一個手指還是可以移動的。

現在,給Wells得到一個高級鍵盤譜(一個僅含0~9的非空字符串)可以在夢裏彈出不輸於鋼琴的旋律,但強迫癥Wells一定要知道高級鍵盤譜彈奏最少要幾秒才能彈完,但Wells數學太差了,所以Wells求助於你,本世紀最優秀的程序yuan之一來幫助他!

Input

輸入文件有若幹行,每行描述一組數據。 對於每組數據僅一行,一個數字串s。

Output

輸出若幹行,每行為對應輸入數據的答案。

Sample Input

434
56
57

Sample Output

5
2
2

Hint

對於20%的數據,0<=length(s)<=5,且數據組數不超過3組; 對於100%的數據,0<=length(s)<=100,且數據組數不超過100組; 保證數據中間沒有空行;


題解:

設dp[i][j][k]為第i個數字左手在j右手在k時的最小秒數。則j或k肯定有一個是當前的數字。先讓j為當前數字枚舉k轉移,再讓k為當前數字枚舉j轉移。從dp[i - 1][l][r]轉移過來,要求是l < r且處理左手在當前數字時l到當前數字的距離+彈奏的1(s)不能比r到k的距離要小,處理右手在當前數字時r到當前數字的距離+彈奏的1(s)不能比l到j的距離小。否則另一只手到達不了另一個數字。

最後f[n][a[n]][i]和f[n][i][a[n]]中最小的即為答案

代碼:

#include<bits/stdc++.h>
using namespace std;
char s[105];
int f[105][15][15];
int a[105];
int main() {
    while (scanf("%s", s + 1) != EOF) {
        int n = strlen(s + 1);
        for (int i = 0; i <= n; i++) {
            for (int j = 1; j <= 10; j++) {
                for (int k = 1; k <= 10; k++) {
                    f[i][j][k] = 0x3f3f3f3f;
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            if (s[i] == '0') a[i] = 10;
            else a[i] = s[i] - '0';
        }
        f[0][5][6] = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j < a[i]; j++) {
                for (int l = 1; l <= 10; l++) {
                    for (int r = l + 1; r <= 10; r++) {
                        int s = abs(r - a[i]) + 1;
                        if (abs(l - j) > s) continue;
                        f[i][j][a[i]] = min(f[i][j][a[i]], f[i - 1][l][r] + s);
                        
                    }
                }
            }
            for (int k = a[i] + 1; k <= 10; k++) {
                for (int l = 1; l <= 10; l++) {
                    for (int r = l + 1; r <= 10; r++) {
                        int s = abs(l - a[i]) + 1;
                        if (abs(r - k) > s) continue;
                        f[i][a[i]][k] = min(f[i][a[i]][k], f[i - 1][l][r] + s);
                    }
                }
            }
        }
        int ans = 0x3f3f3f3f;
        for (int i = 1; i <= 10; i++) {
            if (a[n] < i)
                ans = min(f[n][a[n]][i], ans);
        }
        for (int i = 1; i <= 10; i++) {
            if (i < a[n])
                ans = min(f[n][i][a[n]], ans);
        }
        cout << ans << endl;
    }
    return 0;
}

C(2195):OR

Description

xrdog有一個有趣的算式

X=(a1ora2ora3or...oraN)?YX=(a1ora2ora3or...oraN)?Y

現給定,問有多少組滿足上述算式的,形如 (a1,a2,a3...aN,Y)(a1,a2,a3...aN,Y) 的(N+1)元組。

Input

第一行兩個整數 X(1<=X<=109)X(1<=X<=109) 和 N(1<=N<=109)N(1<=N<=109)

Output

打印一個整數,表示所求答案,答案對1e9+7取模。

Sample Input

2 2

Sample Output

6

Hint

有以下6個3元組: (2,0,1) (0,2,1) (2,2,1) (1,0,2) (0,1,2) (1,1,2)


題解:

先枚舉x的每一個因子,找它的二進制下1的個數,每一個1都有2的n次方 - 1的貢獻,因為只要在n位中或出這個1就可以了,方法除去全為0的1種,即為2的n次方 - 1

註意枚舉因子從1 到 sqrt(x)

代碼:

#include<bits/stdc++.h>
#define p 1000000007
typedef long long ll;
using namespace std;
inline ll fastPow(ll a, ll b) {
    ll ans = 1;
    while (b) {
        if (b & 1) {
            ans = ans * a % p;
        }
        a = a * a % p;
        b >>= 1;
    }
    return ans % p;
}
inline int count(int x) {
    int ans = 0;
    while (x) {
        if (x & 1) ans++;
        x >>= 1;
    }
    return ans;
}
int main() {
    int x, n;
    scanf("%d%d", &x, &n);
    ll base = fastPow(2, n) - 1;
    ll ans = 0;
    for (int i = 1; i * i <= x; i++) {
        if (x % i == 0) {
            int num = count(i);
            ans = (ans + fastPow(base, num)) % p;
            if (i * i != x) {
                num = count(x / i);
                ans = (ans + fastPow(base, num)) % p;
            }
        }
    }
    cout << ans;
    return 0;
}

D(2202):EL PSY CONGROO

Time Limit: 2 sec

Description

鳳凰院兇真又雙叒叕踏上了拯救牧瀨紅莉棲之路,現在有 NN 條世界線 [l1,r1],[l2,r2],...,[lN,rN][l1,r1],[l2,r2],...,[lN,rN]。

從這些世界線中選出 KK 個,考慮其交集,即被所 有 KK 個世界線包含的點集。交集必然也是一個世界線,設為 [l,r][l,r],則其長度為 r?lr?l。

只有世界線的交集最大,岡部才有足夠的時間完成任務。 請求出所有選出 KK 個世界線的方案中,交集長度最大的。

Input

輸入的第一行包含一個整數 TT,代表測試數據的組數。接下來是 TT 組數據。

每組數據的第一行包含兩個整數 NN 和 KK 。接下來NN行,每行包含兩個整數 lili和 riri,描述一 個世界線。

Output

對於每組數據,輸出一行,包含一個整數,代表交集的最大長度。

Sample Input

1
3 2
1 6
2 4
3 6

Sample Output

3

Hint

\[ 1≤T≤1000\1≤K≤N≤10^5\1≤li≤ri≤10^9\∑n≤5?10^5\]


題解:

先對左端點進行升序排序,則選到當前線段的左端點的交集就是當前左端點,同時用小根堆維護右端點的值,使堆大小始終為k,用堆頂的右端點值-當前左端點值更新答案,若超過k,則彈出堆頂的元素,因為它不可能在後面產出更優的答案了

代碼:

#include<bits/stdc++.h>
#define maxn 100050
using namespace std;
inline int getnum() {
    char c; int ans = 0; int flag = 1;
    while (!isdigit(c = getchar()) && c != '-');
    if (c == '-') flag = -1; else ans = c - '0';
    while (isdigit(c = getchar())) ans = ans * 10 + c - '0';
    return ans * flag;
}
struct node {
    int l, r;
    bool operator < (const node a) const {
        return l < a.l;
    }
} a[maxn];
int main() {
    int t = getnum();
    while (t--) {
        priority_queue<int, vector<int>, greater<int> > q;
        int n = getnum(), k = getnum();
        for (int i = 1; i <= n; i++) {
            a[i].l = getnum();
            a[i].r = getnum();
        }
        sort(a + 1, a + n + 1);
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            if (q.size() >= k) {
                q.pop();
            }
            q.push(a[i].r);
            if (q.size() == k) {
                int x = q.top();
                if (x - a[i].l > ans) {
                    ans = x - a[i].l;
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}

E(2203):Mad Scientist

Time Limit: 5 Sec Memory Limit: 256 Mb


Description

鳳凰院兇真是個Mad Scientist,他制造了大量Time Machine分布在一塊 N×MN×M 的矩形網格區域。每格中要麽什麽都沒有,要麽有一個Time Machine。兩個Time Machine之 間的距離定義為其曼哈頓距離。

對於 1≤d≤N+M?21≤d≤N+M?2,兇真想知道有多少對Time Machine的距離恰好為 dd。

Input

輸入的第一行包含一個整數 TT ,代表測試數據的組數。接下來是 TT 組數據。

每組數據的第一行包含兩個整數 NN 和 MM。

接下來 NN 行,每行包含一個長度為 MM 的 0101 串,為‘1’代表網格對應位置中有Time Machine,為‘0’則 代表無。

Output

對於每組數據,輸出一行,包含 N+M?2N+M?2 個整數,其中第 dd 個代表距離為 dd 的Time Machine對數。

Sample Input

1
3 4
0011
0000
0100

Sample Output

1 0 1 1 0

Hint

\[ 1≤T≤3\2≤N,M≤300 \]


題解:

此題愉快的不會,估計也會不了了...orz(流下了蒟蒻的淚水)

思路據說是維護左斜線和右斜線的前綴和,或者二維fft,總之我都不會

感想:

div 1太難了!!!早知道多做會div 2了!!div2倒著做做了兩個題第三題不會就溜了,沒看前兩題挺水的,硬懟div 1大失敗。下次但願能從一開始做,這樣div 1和div 2都有時間做了,中途開始有點傷

csu-2018年11月月賽Round2-div1題解