lwyz's round --- lwyz & tadyz 胡策

前言

紅太陽的題目真是勁啊233.

T1

English

題目描述

小 Q 作爲一名高二黨,面臨着語數英學業水平考試,但他高一沒好好學,非常着急,於是他找到了你,請你來幫助他學習。小 Q 要學的第一門課是英語,可他連字母都不會寫,他打聽到了一個地方,叫兔子街,他要在這學英語。這條街上有連續的 n 所學校,但是一所學校只會教小 Q 所有小寫字母中的一個。 小 Q 只能在連續的一段學校內上學,現在他想寫一個單詞,所以他請你幫忙,算一下他最少需要在幾所學校上學才能寫出這個單詞。

輸入描述

第一行一個數 n,表示有 n 所學校。 接下來一行一個長度爲 n 的僅包含小寫字母的字符串,表示這 n 所學校分別教哪一個字母。第三行一個長度爲 m 僅包含小寫字母的字符串,表示小 Q 想要寫的單詞。 輸出一行一個整數,表示小 Q 至少在幾所學校上學,才能完整的寫出這個單詞。

樣例輸入 1

7 
aabbbcc
abc 

樣例輸出 1

5 

樣例輸入 2

11 
apllaeelpce
apple 

樣例輸出 2

5 

樣例解釋 1

由於小 Q 只能在一段連續的學校內上學,所以他可以在第 2~6 學校學
習,才能學到 abc 三個字母。

樣例解釋 2

小 Q 可以選擇第 2~6 學校或 5~9 學校,都可以學到 a p l e 四個字母,
從而寫出 apple 這個單詞。

數據範圍

對於 20%數據,n,m<=200;
對於 50%數據,n,m<=1000;
對於 100%數據,n,m<=100,0000;
數據保證存在一段連續的學校,使得小 Q 能夠學會整個單詞。
看完題先搞出來暴力,看完t2,,t3後又回來看了下,發現答案符合單調性,於是開始二分亂搞,算了算雖然是100w但二分常數賊小應該卡不住233,事實證明加個手讀比O(n)算法快pwq。考完聽神犇們說可以尺取法O(n)搞,恍然大悟233,不過分一樣還好啦。
代碼如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x = 0 , f = 1;
    char in = getchar();
    while(in < '0' || in > '9')
    {
        if(in == '-')
            f = -1;
        in = getchar();
    }
    while(in >= '0' && in <= '9')
    {
        x = (x << 3) + (x << 1) + in - '0';
        in = getchar();
    }
    return x * f;
}
int n;
char in[1000010];
char ins[1000010];
bool vis[101];
int use[101];
bool check()
{
    for(int i = 0 ; i < 26 ; i ++)
        if(vis[i] && !use[i])
            return false;
    return true;
}
bool check_mid(int mid)
{
    memset(use,0,sizeof(use));
    for(int i = 0 ; i < mid ; i ++)
        use[in[i]-'a'] ++;
    if(check())
    {
        return true;
    }
    for(int i = mid ; i <= n ; i ++)
    {
        use[in[i]-'a'] ++;
        use[in[i-mid]-'a'] --;
        if(check())
        {
            return true;
        }
    }
    return false;
}
int main()
{
    freopen("English.in","r",stdin);
    freopen("English.out","w",stdout);
    n = read();
    scanf("%s%s",in,ins);

    int len = strlen(ins);
    for(int i = 0 ; i < len ; i ++)
        vis[ins[i]-'a'] = 1;
    int l = 1 , r = n;
    while(r - l > 1)
    {
        int mid = l + r >> 1;
        if(check_mid(mid))
            r = mid;
        else
            l = mid;
    }
    if(check_mid(l))
        printf("%d\n",l);
    else
        printf("%d\n",r);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
/*
7
aabbbcc
abc
*/

T2

Chinese.pas/c/cpp

題目描述

小 Q 非常高興你能夠幫他學英語,現在他需要學習語文。首先他需要收集鋼筆。 在兔子街上有連續的 n 家商店,小 Q 想要收集所有 m 支筆,每一支筆會在一個時刻 ci 出現在 di 這一家商店裏。定義一支筆的損耗爲在商店中的時間,也就是被買走的時刻減去被進貨的時刻。 小 Q 召喚了 p 位同學幫他收集, p 位同學聚集在 1 號商店門口,由於同學們非常開心,所以當一位同學出發後,就不會中途停下來,但是你可以決定他們應該什麼時候出發(可以在時刻 0 之前出發),同學們每走 1 單位距離,需要 1 單位時間,可以認爲買筆是不消耗時間的。現在給你這 n家商店之間的距離,求所有筆的損耗加起來最小是多少。

輸入描述

第一行三個正整數 n,m 和 p,表示商店的數量,筆的數量,同學的數量。
第二行 n-1 個正整數,表示第 i 家商店與第 i+1 家商店的距離(di<=10^4)。 接下來 m 行,每行兩個正整數 ai,ci,表示第 i 支筆被 ai這一商店在 ci 時刻進貨。(ai<=ni<=10^9)

輸出描述

一行一個整數,表示所有筆的最小損耗值之和。

輸入樣例

4 6 2 
1 3 5 
1 0
2 1
4 9 
1 10
2 10 
3 12 

輸出樣例

3 

樣例解釋

有 4 家商店,6 支筆,2 位同學。 第一位同學在時刻 0 從 1 號商店出發收集第一支筆,在時刻 1 時到達 2 號商店收集第二支筆,在時刻 9到達 4 號商店,收集第三支筆,損耗均爲 0;第二位同學在時刻 10 從1 號商店出發收集第 4 支筆,在時刻 11 到達 2 號商店收集第 5 支筆,損耗爲 1,在時刻 14 到達 3 號商店收集第 6 支筆,損耗爲 2。總消耗爲 3;這是總損耗最小的方案。

數據範圍

對於 20%數據,p=1;
對於另外 30%數據,n,m,p<=7;
對於 100%數據 n,m<=500; p<=50;
考試結束前半小時把到每個筆的時間的數組輸出了下突然發現是個劃分dp,趕緊碼了一個,然而並沒有什麼用233,dp[m][p] 是前 m 支筆用 p 個同學去拿,轉移方程見代碼
代碼如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int size = 1010;
ll read()
{
    ll x = 0 , f = 1;
    char in = getchar();
    while(in < '0' || in > '9')
    {
        if(in == '-')
            f = -1;
        in = getchar();
    }
    while(in >= '0' && in <= '9')
    {
        x = x * 10 + in - '0';
        in = getchar();
    }
    return x * f;
}
struct apple_pen
{
    ll p,a,c;
}pen[size];
ll n,m,p,num[size],sum[size];
ll pen_time[size];
ll sum_time[size];
ll f[501][70];
int main()
{
    freopen("Chinese.in","r",stdin);
    freopen("Chinese.out","w",stdout);
    n = read() , m = read() , p = read();
    for(int i = 1 ; i < n ; i ++)
        num[i] = read() , sum[i] = sum[i-1] + num[i];
    for(int i = 1 ; i <= m ; i ++)
        pen[i].p = i , pen[i].a = read() , pen[i].c = read();
    int ans = 0;
    for(int i = 1 ; i <= m ; i ++)
        pen_time[i] = pen[i].c-sum[pen[i].a-1];
    sort(pen_time+1,pen_time+1+m);
    for(int i = 1 ; i <= m ; i ++)
        sum_time[i] = sum_time[i-1] + pen_time[i];
    for(int i = 1 ; i <= m ; i ++)
        for(int j = 1 ; j <= p ; j ++)
            f[i][j] = 21474836471111ll;
    for(int i = 1 ; i <= m ; i ++)
        f[i][1] = i * pen_time[i] - sum_time[i];
    for(int i = 1 ; i <= m ; i ++)
        for(int j = 2 ; j <= p ; j ++)
            for(int k = 1 ; k < i ; k ++)
                f[i][j] = min(f[i][j],f[k][j-1] + (i-k)*pen_time[i] - sum_time[i] + sum_time[k]);
    printf("%lld\n",f[m][p]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
/*
3 3 1
1 3 
1 0
2 1 
3 3

4 6 2 
1 3 5 
1 0
2 1
4 9 
1 10
2 10 
3 12
*/

T3

Math.pas/c/cpp

題目描述

小 Q 終於來到了最後一部分——數學。他想要去找數學老師給自己輔導功課,數學老師爲了考察他的智商,給他出了一道難題。老師給小 Q一個座標系,上面有 N 個點,每個點的座標爲非負整數。現在老師想要讓小 Q 恰好刪掉其中 k 個點,使得剩下的點兩兩之間距離的最大值儘量小。於是小 Q 找到了你,請你幫忙解決這一問題。兩點間距離=sqrt((x1-x2)²+(y1-y2)²)

輸入描述

第一行兩個正整數 n,k,分別代表點的數量和需要刪掉點的數量。
接下來 n 行, 每行兩個整數, 描述一個點的座標,這些點按照給出順序進行標號,編號爲 1~n。

輸出描述

一行 k 個數,表示需要刪掉點的編號。如果有多組解,輸出任意一組。
輸入樣例 1 輸入樣例 2
5 2 4 1
1 2 0 0
0 0 0 0
2 2 1 1
1 1 1 1
3 3
輸出樣例 1 輸出樣例 2
2 5 2

樣例解釋 1

刪除 2 號點與 5 號點後,最大距離爲 3 號與 4 號點距離≈1.41421

樣例解釋 2

刪除任意一點後,兩點之間的最大值都≈1.41421,所以輸出任意一點
都正確。

數據範圍

N<=1000 K<=30
雖然答案符合單調性,但還是是個np問題,正解是爆搜加減枝,貌似減枝後的複雜度是可以證明與fib相關的,不是很懂。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章