Codeforces Round #652 div2 總結 & 端午節前小結

2020.6.24
連着三天熬夜和一連串要處理的事情已然讓我的身體有點喫不消。我只是喜歡想題的那種冥想思路開闊的感覺,但是熬夜還是不能行的。端午節前就暫時不碰競賽了,昨天晚上算是打完了最後一場比賽。今天補完d就去打打pubg放鬆一下。

昨天自閉了一天之後晚上緊接着又是開幕雷擊。本來以爲是22:35的比賽因爲我記錯時間晚了10min纔到。上一秒還在津津有味地看着洛穀日報。qq叮叮叮地響了起來,我一看,朋友問我a會麼,我這時候才意識到,完犢子,這都開始了我竟然不知道。吃了一驚的我顯然並沒有被這一番事情把原本地節奏打亂,而是不慌不忙地下樓拿我買的coco蜜桃紅茶凍,不得不說真的蠻好喝的

好了,言歸正傳,看題。首先我打開cf的時候已經5k人過了A,我自閉了,這還怎麼翻盤啊?

仔細看了看A,題意是問一個正n邊形在xOy平面內能不能在旋轉的時候保證有邊分別平行於x和y。從大一之後我好久沒碰幾何數學了,還有點懷念高中手撕雙曲線,橢圓這些圖形的時候,現在有點陌生了哎,前幾天老師還喊我去給高中學弟學妹輔導數學,我。。。。。咳咳,懷什麼久,好好看題。好吧,這道題非常顯然了,看的時候就想到那就轉化爲4條平行於座標軸的邊,旁邊再塞其他邊唄,不難發現塞進去多加的邊上下都必須保持一致來維護原狀態,那就。。。mod 4看能不能除掉就行了。然後我眼疾手快地把4寫成了2wa了一發hhhh。不過好在改了之後過了,但這特麼都排到1w名了這還怎麼翻盤??
代碼:

#include <bits/stdc++.h>
using namespace std;
#define limit (400 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步兩步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(int i = a; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 988244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
    return x * sign;
}//快讀
void write(ll x){
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
int n,k;
int main() {
#ifdef LOCAL
    FOPEN;
#endif
    int kase;
    cin>>kase;
    while(kase--){
        cin>>n;
        if(n % 4 != 0)cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
    return 0;
}

B題一般是離散數學的內容,一看果然是,看是給一個01串然後如果出現10這種就可以刪掉兩個其中任意一個字符,輸出在若干次刪除之後字典序最小的串。這題直接模擬肯定會t,肯定要有更好的算法。手動模擬了下,直接考慮分類討論:
1)如果不存在10子串,那麼就不存在刪的可能,直接輸出原字符串。
2)顯然,開頭連續的0和結尾連續的1不可能刪除,無論中間間隔是什麼,一定原本出現在答案中
3)中間,如果存在開頭連續0和結尾連續1之外的子串,那麼這些子串無論如何都可以被縮減至只剩一個0,因爲要字典序最小嘛,一個1也是可以,但是不符合題意。
好了,有了這些就從兩頭分別掃一遍0和1,加到兩個string裏面去,記錄下停止的下標,如果開頭的0和結尾的1不接壤,那麼拼接前後的時候中間就添加一個0,如果接壤就直接拼接前綴和後綴。也沒那麼難嘛,數組沒開夠re了一發,中間沒考慮不加0的情況wa2了一發,然後ac,總算排名回到了6k。
代碼:

#include <bits/stdc++.h>
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步兩步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(int i = a; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 988244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
    return x * sign;
}//快讀
void write(ll x){
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
int n,k;
int a[limit],b[limit];
int main() {
#ifdef LOCAL
    FOPEN;
#endif
    int kase;
    cin>>kase;
    while(kase--){
        string str;
        cin>>n>>str;
        string s = str;
        str = ' ' + str;
        int flag = 1;
        string ans,pre;
        rep(i ,1, n - 1){
            if(str[i] == '1' && str[i + 1] == '0'){
                flag = 0;
                break;
            }
        }
        if(flag){
            cout<<s<<endl;
            continue;
        }
        int fst,scd;
        per(i,1,n){
            if(str[i] == '0'){
                scd = i;
                break;
            }
            ans += '1';
        }
        rep(i ,1,n){
            if(str[i] == '1'){
                fst = i - 1;
                break;
            }
            pre += '0';
        }
        if(fst != scd){
            ans = pre + '0' + ans;
        }else{
            ans = pre + ans;
        }
        cout<<ans<<endl;
    }
    return 0;
}

然後開C,C題意是問有數列a和b,大小分別爲n和k,a代表數字,bi代表可以從a拿的個數,b的和等於a的大小,對每個bi都有一個值,分配到的最小和最大的數字之和,問這些數字能分配之後b的值的和最大是多少。肯定不能暴力(廢話)。剛看到的時候有點懵。既然說大小那排個序肯定是說的過去的,排着序就想到首先讓最大值最大化,那麼最大的k個值無論放在哪都是最大,先每個放一個,然後讓bi - 1。還剩n-k個值,要讓最小值最大化那麼首先就要減少在鋪墊過程中的損失,那就是從bi最小的開始放,然後統計一下答案就行了,結果又re了一發才過,我瘋了,2e6明明可以用的int的結果爆炸了hhh。排名到3k了,還行,其實今天不掉分的任務已經完成了,再去看看d。
代碼:

#include <bits/stdc++.h>
using namespace std;
#define limit (1000000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步兩步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(int i = a; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 988244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
    return x * sign;
}//快讀
void write(ll x){
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
int n,k;
int a[limit],b[limit];
int maxx[limit],minn[limit];
int main() {
#ifdef LOCAL
    FOPEN;
#endif
    int kase;
    cin>>kase;
    while(kase--){
        cin>>n>>k;
        rep(i ,1,n){
            cin>>a[i];
        }
        sort(a + 1, a + 1 + n,greater<>());
        rep(i ,1,k){
            cin>>b[i];
            maxx[i] = -INF;
            minn[i] = INF;
        }
        sort(b + 1, b + 1 + k);//反向sort一遍
        rep(i ,1,k){
            maxx[i] = minn[i] = a[i];
            --b[i];//撿一個
        }
        int it = 0;
        rep(i,1,k){
            if(b[i] > 0){
                minn[i] = a[k + it + b[i]];
                it += b[i];
            }
        }
        ll ans = 0;
        rep(i ,1,k){
            ans += (minn[i] + maxx[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

D,1e9+7取模還多組答案一眼看出是遞推或者dp預處理這樣,然而11點左右打到D我腦子有些鈍了不太能看得出來,查oeis也沒查出來什麼有用的信息。就去看E,E看了之後感覺是拓撲排序/容斥or費用流,然而這仨中拓撲排序我會一點,容斥和費用流我太菜不會啊(今天跳到一堆費用流的題應該說是瘋狂暗示了,然而我直接關了),然後又去看D。手動模擬了一下發現從答案的貢獻的增量應該是有一個週期爲2的增長,然後中間每個增量過2個週期又開出一朵新的花。那就寫寫,結果最後也沒有調出來,從10開始就不對了也沒幹交,結果今天早上看到羣友的寫的就發現我蠢了,旁邊的樹杈增量是2不是4,怪不得出鍋,哎,昨天罰時吃了點虧,掉到4k了只漲了17分,如果按時好好做的話應該是2k左右,然而這能怪誰呢?re和看錯時間還是自己的鍋,下次注意吧。端午節前就這樣,等會去喫飯,放鬆一下,節後備戰牛客多校。
代碼:

#include <bits/stdc++.h>
using namespace std;
#define limit (3000000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步兩步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(int i = a; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 988244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
    return x * sign;
}//快讀
void write(ll x){
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
int n,k;
const ll mod = 1e9 + 7;
ll dp[limit],delta[limit];
int main() {
#ifdef LOCAL
    FOPEN;
#endif
    int kase;
    cin>>kase;
    dp[3] = dp[4] = 4;
    delta[3]  = 1;
    delta[4] = 0;
    rep(i ,5, 2e6){
        (dp[i] = dp[i - 1] + 2 * dp[i - 2]) %= mod;
        if(!delta[i - 1] && !delta[i - 2]){
            (dp[i] += 4) %= mod;
            delta[i] = 1;
        }
    }
    while(kase--){
        cin>>n;
        if(n == 1 || n == 2){
            puts("0");
            continue;
        }
        cout<<(dp[n]%mod)<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章