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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章