Educational Codeforces Round 83 (Rated for Div. 2) (A-E)

Educational Codeforces Round 83 (Rated for Div. 2)

emm马上绿了XD


A
正多边形内部接一个正多边形。
根据对称性只要顶点数可以整除即可。

B
构造。
将原序列按单调不增的顺序排序,那么新序列依次减去一个递增的项之后一定可以得到一个递减序列。

C
在一串全0串中允许对某个元素添加一次 k i k^i ki,一个 k i k^i ki只能被使用一次,问是否能够经过若此操作后获得给出的序列。

惨遭Hacked…假的一比的算法居然能过11个pretest…
这么看来其实pretest故意不给出所有情况,那么如果对某道题有了深刻全面的理解后,就可以去找题目的漏洞hack别人了??

维护一个桶,记录为了到达给定序列需要的 k i k^i ki的个数。这里要注意的地方是,该表达方式 不是k进制! k进制允许某一位出现 0 , 1 , . . . , k − 1 0, 1, ..., k - 1 0,1,...,k1,但这道题只允许在每一位出现 0 和 1 0和1 01(我太傻逼了) !

改了之后飞快的AC。

D
组合计数。

先在m个元素里取n-1个,然后选择除了最大项的一项进行复制,由此构造n个元素:
单独考虑n==2的情况,此时最终只会取出来两个一样的元素,无法形成山峰形状,因而输出0。在其余情况下,对于m中取出来的n-1个元素,不妨离散化地考虑他们就是 1 , 2 , … , n − 1 1,2,\dots, n -1 1,2,,n1
此时要复制一个元素只有可能是从1到n-2中选择一个。

之后开始构造山峰形状:
因为严格单调增单调减,那么复制过的元素显然无法在同一侧,也就是必须分布在两侧。这样操作以后两侧已经拥有了一个元素,就不需要考虑是否为0元素的情况,那么只要在剩下的n-3个元素找到一个长度为 i ( i = 0 , 1 , . . . , n − 3 ) i(i = 0, 1, ..., n - 3) i(i=0,1,...,n3)的单调序列即可。因为n-3个元素两两不同,因而任意取一组i个元素都一定可以用他们构造一组单调序列。

所以综上考虑,最终结果为:
( n − 1 m ) ∗ ( n − 2 ) ∗ 2 n − 3 (^{m}_{n-1}) * ( n -2)*2^{n-3} (n1m)(n2)2n3

E
想了非常久,但是没有想出来怎么dp。
我考虑时最开始的dp想法是不具有对称性的,也就是顺序遍历i,考虑[1, i]的合并情况,这样子dp其实很难满足题意要求的合并规则,最后有一点想到可能是区间dp,但是并没有太多的想法来解决该问题。

正确的做法学习于:Educational Codeforces Round 83 (Rated for Div. 2)

区间dp
区间dp[maxn][maxn]记录区间[i, j]是否可能被合并为一个数,如果可能则记录该数,不然则置为-1. 如何递推呢?如果要求解dp[i][j],可以将k从i遍历到j:如果区间[i, k]和区间[k + 1, j]各自都可以化简到一个数并且这两个数都是 x x x,那么dp[i][j]就可以合并到 x + 1 x+1 x+1
获取dp数组的时间复杂度为 O ( n 3 ) O(n^3) O(n3),这是因为对于一共 n 2 n^2 n2组区间,每组区间都搜索一边中间所有点来更新当前区间。为此我们还需要进行一些时间的优化手段: 记忆化。如果引入vis数组进行记忆话搜索的话时间复杂度就会降到 O ( n 2 ) O(n^2) O(n2),这样的时间消耗是可以接受的。

之后就可以根据dp数组 O ( n 2 ) O(n^2) O(n2)的获得答案: 对于某个位置,查询之前所有位置(包括0),如果这一段区间可以合并为一个点,就用之前位置的长度再加一来更新当前位置的长度,如是反复即可。

const int maxn = 5e2 + 10;

int n;
int a[maxn];
int ok[maxn][maxn], vis[maxn][maxn];

int dp(int x, int y){
    if(vis[x][y]) return ok[x][y];
    vis[x][y] = 1;
        
    if(x == y) return ok[x][y] = a[x];
    for(int i = x; i < y; i++)
        if(dp(x, i) == dp(i + 1, y) && ok[x][i] != -1) return ok[x][y] = ok[x][i] + 1;
    
    return ok[x][y];
}

int ans[maxn];

void de(){
    for(int i = 1; i <= n; i++){
        for(int j = i; j <= n; j++) printf("%d ", ok[i][j]);
        printf("\n");
    }
}

int main(){
//    Fast;
    memset(ok, -1, sizeof ok); memset(ans, 0x3f, sizeof ans);
    scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", a + i);
    dp(1, n);
    ans[0] = 0;
    for(int i = 1; i <= n; i++) for(int j = 1; j <= i; j++){
        if(ok[j][i] != -1)
            ans[i] = min(ans[i], ans[j - 1] + 1);
    }
    printf("%d\n", ans[n]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值