A - Forgetting Things

题意:给 \(a,b\) 两个数字的开头数字(1~9),求使得等式 \(a=b-1\) 成立的一组 \(a,b\) ,无解输出-1。

题解:很显然只有 \(a=b\) 和 \(a=b-1\) 的时候有解,再加上一个从 \(9\) 越到 \(10\) 的就可以了。被样例的 \(199,200\) 误导了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int a, b;
while(~scanf("%d%d", &a, &b)) {
if(a == b)
printf("%d %d\n", a * 10, b * 10 + 1);
else if(a == b - 1)
printf("%d %d\n", a, b);
else if(a == 9 && b == 1)
printf("9 10\n");
else
puts("-1");
}
}

B1 - TV Subscriptions (Easy Version)

见下一题

B2 - TV Subscriptions (Hard Version)

题意:有n天,每天上映一段电视剧的第ai节,要连续看d天,求最少买多少张票。注意买了某一节的票之后就可以反复看这一节。

题解:看数据量,是不是可以二分票的张数,然后尺取暴力验证呢?不过真的t会卡memset,而k的上限又没给,假如想用memset的话要先进行一次离散化。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; int n, k, d;
int a[200005];
int cnt[1000005]; bool check(int m) {
int cur = 0;
for(int i = 1; i <= d; ++i) {
++cnt[a[i]];
if(cnt[a[i]] == 1)
++cur;
}
if(cur <= m) {
for(int i = 1; i <= d; ++i)
cnt[a[i]] = 0;
return 1;
}
for(int i = d + 1; i <= n; ++i) {
++cnt[a[i]];
if(cnt[a[i]] == 1)
++cur;
--cnt[a[i - d]];
if(cnt[a[i - d]] == 0) {
--cur;
if(cur <= m) {
for(int j = 0; j < d; ++j)
cnt[a[i - j]] = 0;
return 1;
}
}
}
for(int j = 0; j < d; ++j)
cnt[a[n - j]] = 0;
return 0;
} int bs() {
int l = 1, r = d, m;
while(1) {
m = (l + r) >> 1;
if(l == m) {
if(check(l))
return l;
return r;
}
if(check(m))
r = m;
else
l = m + 1;
}
} int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &n, &k, &d);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
printf("%d\n", bs());
}
}

补题题解:其实并不需要二分,扫的时候就知道最小值是谁了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; int n, k, d;
int a[200005];
int cnt[1000005]; int solve() {
int cur = 0;
for(int i = 1; i <= d; ++i) {
++cnt[a[i]];
if(cnt[a[i]] == 1)
++cur;
}
int mincur = cur;
for(int i = d + 1; i <= n; ++i) {
++cnt[a[i]];
if(cnt[a[i]] == 1)
++cur;
--cnt[a[i - d]];
if(cnt[a[i - d]] == 0) {
--cur;
if(cur < mincur)
mincur = cur;
}
}
for(int j = 0; j < d; ++j)
cnt[a[n - j]] = 0;
return mincur;
} int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d%d", &n, &k, &d);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
printf("%d\n", solve());
}
}

C - p-binary

题意:给一个整数n,求它最少用多少个p-binary数组成,无解输出-1,p-binary数是指形如 \(2^x+p\) 的数,其中x非负。

题解:看了下样例,感觉就是不断的尝试减去p(记总共减去了cnt个p),然后判断新的n能不能被cnt个二进制位所表示。不过样例提示我们可以用多个相同的二进制位合成一个高位,所以只需要新的n的二进制位数量不超过cnt就可以了。不过这样做卡了一个数据就是n=101,p=50,这个是输出-1,我这样写输出2,原因是1并不能被2个二进制位表示,因为不能取x=-1,所以得到另一个启发就是k个二进制位能表示的下限就是k(k个1相加),上限是无穷,但是能表示的数必须不超过cnt个1。

为什么比cnt少的二进制位都可以构造呢?因为可以用两个小的组成一个大的来使得cnt变相减少1,而这种方法使用的下限就是cnt个1。

顺带提一下__builtin_popcount()这个函数,其他的不好用但是这个(以及__builtin_ctz()返回后导零的个数)还是不错的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int n, p;
while(~scanf("%d%d", &n, &p)) {
int cnt = 0;
while(cnt < 40) {
n -= p;
if(n <= 0) {
cnt = -1;
break;
}
++cnt;
if(__builtin_popcount(n) <= cnt && n >= cnt)
break;
}
if(cnt == 40)
cnt = -1;
printf("%d\n", cnt);
}
}

D - Power Products

题意:给 \(n\)(2e5)个1e5内的数和 \(k\) (100),求有多少个无序数对 \((i,j)\) 满足存在一个 \(x\) 使得 \(a_ia_j=x^k\) 成立。

题解:

很显然就是每种质因数都要是k的倍数,那么每个数要找的那个数是在模意义下面唯一的,一个暴力的做法是分解1e5内的质数,然后求出不超过1e5的这个质数的最高幂,很明显这个最高幂很快就收敛到只剩下1了,那么可以用一个next指针为[0,16](也就是log(2,1e5))的字典树来存储。这样到后面一般只有两条路可以走。问题在于由于质数过多深度太大。

一种简单的改进就是特判掉k=2的情况,然后质数的范围就真的缩小到sqrt(1e5),超过这个范围的质数最多只有一个,且出现以后不可能会和另一个数配出k>=3时的k的倍数。这样是大概只有65层的一个字典树。

那怎么特判掉k=2的情况呢?应该是存在同一个大质因数的放在一堆,然后堆内匹配。不存在任何大质因数的也是一堆,也是堆内匹配。

补题题解:

本质上是要找唯一配对的一个质因数幂次序列,使用字典树会导致单次修改要经历所有的质数。其实根据唯一分解定理,把这些质因数幂次序列转回去整数存储就可以了,不用搞这么复杂。直接把一个数映射到幂模k的另一个数,然后用map存下来就可以了。甚至不需要用map,他的补数也必须限制在1e5里面的,在找补数的时候注意溢出就可以(使用map的话,应该是可以连溢出都不用管,因为溢出之后大部分应该是找不到答案,应该没有概率说溢出之后绕回来到1e5内)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int MAXAI = 1e5;
int cnt[100005]; int p[105], ptop;
bool np[405]; ll qpow(ll x, int n) {
ll res = 1;
while(n) {
if(x > MAXAI)
return -1;
if(n & 1) {
res = res * x;
if(res > MAXAI)
return -1;
}
x = x * x;
//不能在这里判断x溢出,因为有可能这个x不会叠到res上
n >>= 1;
}
return res;
} int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
for(int i = 2, c = sqrt(MAXAI); i <= c; ++i) {
if(np[i])
continue;
p[++ptop] = i;
for(int j = i + i; j <= c; j += i)
np[j] = 1;
} int n, k;
scanf("%d%d", &n, &k);
ll ans = 0;
for(int i = 1, ai; i <= n; ++i) {
scanf("%d", &ai);
ll bi = 1, ci = 1;
for(int j = 1; j <= ptop; ++j) {
if(ai % p[j] == 0) {
int ki = 0;
while(ai % p[j] == 0) {
++ki;
ai /= p[j];
}
ki %= k;
if(ki) {
//假如ki==0,那么k-ki==0,bi和ci都不会变化
ci *= qpow(p[j], ki);
if(bi != -1) {
ll tmp = qpow(p[j], k - ki);
if(tmp != -1) {
bi *= tmp;
if(bi > MAXAI)
bi = -1;
} else
bi = -1;
}
}
}
}
if(ai > 1) {
ci *= ai;
if(bi != -1) {
ll tmp = qpow(ai, k - 1);
if(tmp != -1) {
bi *= tmp;
if(bi > MAXAI)
bi = -1;
} else
bi = -1;
}
}
if(bi != -1)
//当bi不溢出时,看看前面是不是已经统计了这个bi
ans += cnt[bi];
++cnt[ci];
}
printf("%lld\n", ans);
}

注:快速幂里面的溢出不是在x=x*x之后判断,因为有可能会有n>>=1之后n==0,也就是最后一步并不会让res叠上x。

标签:质因数分解

E - Rock Is Push

题意:一个n*m(2000*2000)的棋盘格,每次只能向右或向下走,求走到最右下的不同路径数.注意棋盘格上有石头,可以推动石头,也可以推动一串石头,但是不能把石头推出边界。

补题题解:很显然的一个dp,但是要怎么入手呢?先说一个显然的结论,就是当前行/列的石头只会影响你在这个行/列上前进的终点,在改变方向只会这些石头会再有没有用,所以说每次只需要考虑当前方向上的石头即可。

\(dp[i][j][0]\) 表示从左侧走到格子 \((i,j)\) 的方案数。

\(dp[i][j][1]\) 表示从上侧走到格子 \((i,j)\) 的方案数。

那么怎么转移呢?举个例子,比如现在求的是 \(dp[i][j][1]\) ,从上方进来的话,会有最后一次向右走的位置,记这个位置为 \((k,j)\) ,也就是从左侧进入了 \((k,j)\) ,然后一直往下到 \((i,j)\) ,什么是合法的 \((k,j)\) 呢?当然就是 \((k,j)\) 下方的石头的数量不超过 \((i,j)\) 下方的空格的数量的 \((k,j)\) ,可以看出来随着 \(k\) 不断往上途径的石头会越来越多,这个转折点是确实存在的。一个细节在于这个 \((k,j)\) 这行能不能通过向右走到 \((k,j)\) 是无关紧要的,反正也就加在一起,事实上 \((k,j)\) 应该是上边界某点或者正好在某块石头上(这块石头会被向右推走而不会被向下推,k再上升则会被向下推)

也就是 \(dp[i][j][1]=\sum\limits_{t=k}^{i-1}dp[t][j][0]\)

同理有 \(dp[i][j][0]=\sum\limits_{t=k}^{j-1}dp[i][t][1]\)

方程有了,边界怎么办? \((1,1)\) 格子既可以视作从左侧来也可以视作从上侧来,只是 \(n=m=1\) 的时候要特判掉。

怎么找k呢?以向下转移为例,很显然每个格子下方的石头数是递增的,可以保存每一行每一列的值直接二分,鉴于数据只有2000所以多个11倍常数问题不大。另一种方法是直接从上方的格子转移。

参考资料:

Technocup 2020 — Elimination Round 2 + Codeforces Round 596: analysis - Codeforces

CodeForces 1225E Rock Is Push(dp + 前缀和优化) - alpc_qleonardo - CSDN博客

Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2)的更多相关文章

  1. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) D. Power Products

    链接: https://codeforces.com/contest/1247/problem/D 题意: You are given n positive integers a1,-,an, and ...

  2. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) C. p-binary

    链接: https://codeforces.com/contest/1247/problem/C 题意: Vasya will fancy any number as long as it is a ...

  3. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) B2. TV Subscriptions (Hard Version)

    链接: https://codeforces.com/contest/1247/problem/B2 题意: The only difference between easy and hard ver ...

  4. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) A. Forgetting Things

    链接: https://codeforces.com/contest/1247/problem/A 题意: Kolya is very absent-minded. Today his math te ...

  5. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) F. Tree Factory 构造题

    F. Tree Factory Bytelandian Tree Factory produces trees for all kinds of industrial applications. Yo ...

  6. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) E. Rock Is Push dp

    E. Rock Is Push You are at the top left cell (1,1) of an n×m labyrinth. Your goal is to get to the b ...

  7. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) B. TV Subscriptions 尺取法

    B2. TV Subscriptions (Hard Version) The only difference between easy and hard versions is constraint ...

  8. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) A. Forgetting Things 水题

    A. Forgetting Things Kolya is very absent-minded. Today his math teacher asked him to solve a simple ...

  9. Codeforces Round #596 (Div. 2, based on Technocup 2020 Elimination Round 2) D. Power Products 数学 暴力

    D. Power Products You are given n positive integers a1,-,an, and an integer k≥2. Count the number of ...

随机推荐

  1. 本地计算机上的mysql服务启动停止后,某些服务在未由其他服务或程序使用时将自动停止

    C:\Windows\system32>cd C:\Program Files\mysql-8.0.18-winx64\bin\ C:\Program Files\mysql-8.0.18-wi ...

  2. C++复制构造函数,类型转换构造函数,析构函数,引用,指针常量和常量指针

    复制构造函数形如className :: className(const &)   /   className :: className(const className &)后者能以常 ...

  3. .net core的startup中配置读取

    public class Startup { public Startup(IHostingEnvironment env) { Configuration = new ConfigurationBu ...

  4. 这些方面做好了才能叫运营-App运营日常

    现在APP的开发推广是时代的潮流,同时也是不少企业的难题.现在我们就来谈谈APP运营的一些问题. 1. 基础运营正常维护产品最日常.最普通的工作,如APP应用包在各大应用市场提交上传等,如安卓渠道,包 ...

  5. MySQL常见问题集锦及注意事项

    一.表设计上的坑 1.字段设计 1.1 字段类型设计 尽量使用整型表示字符串: `INET_ATON(str)`,address to number `INET_NTOA(number)`,numbe ...

  6. py-1 语言介绍

    一.编程与编程语言 1.编程的目的 计算机的发明,是为了用机器取代并解放人力.而编程的目的则是将人类的思想流程按照某种能够被计算机识别的表达方式传递给计算机,从而达到让计算机能够像人脑.电脑一样自动执 ...

  7. oracle concepts学习

    祭图一张!!!

  8. SLAM、三维重建,语义相关数据集大全

    作者朱尊杰,公众号:计算机视觉life,编辑成员 一 主要针对自动驾驶: 1.KITTI数据集: http://www.cvlibs.net/datasets/kitti/index.php(RGB+ ...

  9. 使用宏定义来判断是a和b 的大小

    #include <stdio.h> #include <math.h> #define MAX(a, b) (a) > (b) ? printf("a > ...

  10. 实验十一 团队作业7:团队项目设计完善&编码1

    博文简要信息表: 项目 内容 软件工程 https://www.cnblogs.com/nwnu-daizh/ 本次实验链接地址 https://www.cnblogs.com/nwnu-daizh/ ...