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. solr的post.jar

    http://iamyida.iteye.com/blog/2207920   跟益达学Solr5之玩转post.jar

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

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

  3. vue使用技巧:Promise + async + await 解决组件间串行编程问题

    业务场景描述 大家都通过互联网投递过简历,比如在智联.58.猎聘等平台.投递心仪的职位前一般都需要前提创建一份简历,简历编辑界面常规的布局最上面是用户的个人基本信息,如姓名.性别.年龄.名族等,接着是 ...

  4. 本地数据存储解决方案以及cookie的坑

    本地数据存储解决方案以及cookie的坑 问题: cookie过长导致页面打开失败 背景: 在公司的项目中有一个需求是打开多个工单即在同一个页面中打开了多个tab(iframe),但是需要在刷新时只刷 ...

  5. vue中将时间戳转换为YYYY-MM-dd hh:mm格式时间的组件

    首先我们可以使用vue中的过滤方法将数据变成另一个格式 // html <span class="rate-time">{{rating.rateTime | form ...

  6. U-Boot补丁 S3C2440

    # tar xvf u-boot-1.1.6.tar.bz2 //解压 # cd u-boot-1.1.6/ 制作补丁文件 # diff -urN u-boot-1.1.6 u-boot-1.1.6. ...

  7. Django 启动报错 UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc7

    pycharm 报错 cmd 报错 解决办法 首先 是计算机 编码问题  是 django 读取你的  用户host名 但是 windos 用户名 如果是中文 就会报这个错  要改成 英文

  8. Oracle死锁处理实例

    Oracle死锁常规语句 1.查询Oracle死锁常规语句 SELECT l.session_id sid, s.serial#, l.locked_mode,l.oracle_username, l ...

  9. 如何11 周打造全能Python工程师!

    在这个大数据和人工智能的时代,不管你是编程初学者,还是想学习一门其他语言充实自己,Python都是最好的选择之一. 它简洁.优雅.易学,被越来越多的大学作为计算机新生的入门语言: 它是大数据和人工智能 ...

  10. inotify文件监控

    参考:xxxx /*************************************************************************\* Copyright (C) M ...