鉴于本人最近智商和代码能力有明显下降趋势(年纪大了,没办法),准备刷CF保健康。
昨天选了第一版最后一个比赛,#206的div2 (怕div1 太难,做不出来)。
花了点时间,做了4题,D题不会(最后憋不住,看题解,结果看了也不会,而且看rng58的代码也看不明白,太弱了)
---------------------------------------------------我是分割线-----------------------------------------------
A . Vasya and Digital Root
题意
构造一个整数x,把x的数码累加和不断迭代直到这个值小于10,作为x的根r。现在给你r和x的位数k,要你构造出满足条件的x。
思路
x > 0 时,假设 d = x%9 ,如果 d = 0 ,则r 为9 ,其他的时候为d。证明很简单,把x拆成a_i*10^i的形式,数码和,提一个9出来就可以。
r = 0 时, x 一定是0。
所以构造的时候构造 9000..00r 这种数就可以了,r=0的时候特判一下就可以了。
题意
构造一个整数x,把x的数码累加和不断迭代直到这个值小于10,作为x的根r。现在给你r和x的位数k,要你构造出满足条件的x。
思路
x > 0 时,假设 d = x%9 ,如果 d = 0 ,则r 为9 ,其他的时候为d。证明很简单,把x拆成a_i*10^i的形式,数码和,提一个9出来就可以。
r = 0 时, x 一定是0。
所以构造的时候构造 9000..00r 这种数就可以了,r=0的时候特判一下就可以了。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<n;i++)
#define FD(i,n) for(i=n-1;i>=0;i--)
#define EPS 1e-8
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;
int main(){
int k,d;
cin >> k >> d;
if(d==0){
if(k==1) cout << 0 << endl;
else cout << "No solution" << endl;
}
else {
if(k==1) cout << d << endl;
else{
int i;
cout << 9;
FU(i,k-2) cout << 0;
if(d) cout << d << endl;
else cout << 9 << endl;
}
}
return 0;
}
----------------------------------------------------------我还是分割线--------------------------------------
B. Vasya and Public Transport
题意
坐巴士和电车,有4种票
1 单程票,只能坐某个车1次
2 单车票,可以坐某个车无限次次
3 单类票,可以坐所有的巴士或者所有的电车无限次次
4 全票,可以无限制坐无限次。
给你要坐的巴士和电车的线路和次数,问你最小花费。
思路
简单贪心。
首先全票肯定可以全部搞定。
针对某一类,最多是一张单类票。
对于某一单类的每个线路,贪心计算,如果单程票*次数 > 单车票,那就选单车票,否则选单程票。
最后看这个价格是否超过单类票,取小的。
两类的最小花费之和如果小于全票,那就取这个花费即可。
代码写的比较挫,c+v了一下。
C.
题意
给你一排N个物品组成的双端队列,机器人去取,单位耗费从左取的是L,从右取是R。
如果连续从左取,附加耗费是 QL;连续从右取,附加耗费是QR。
问你取完的最小耗费。
思路
首先和括号匹配一样,不会出现RL这种取法,所以一定是从某一点分开,左边的全部从左取,
右边的全部从右取。显然交替取的代价比连续取低,所以某一点分开,基础代价是
左边重量和*L+右边重量和*R ,
额外的耗费,令 t = 右边次数 - 左边次数。
如果t > 1 ,那么加上 (t-1) * QR;
如果t< -1 那么加上 (-t-1) * QL。
综上,预处理左边重量累加和和右边重量累积和,然后扫一遍,计算每个分割点的搬运代价,
取极小即可。
奇怪的是,我的INF设成0x33333333居然会WA,设成0x3f3f3f3f就AC了。而我拿那个WA的数据本地跑
又不会WA。。。不知道为什么
。
----------------------------------------------------------我继续是分割线---------------------------------------
D.
题意
一个n*n(n<=20)的矩阵,每个元素是一个小写英文字母,从左上到右下,只能向下和向右走,每次走一步。
两人聪明人轮流走,其路径构成的字符串中如果字符a多,那么第一个人赢;
如果字符b多,那么第二人赢;相同则平局。问最后的结果。
思路
直觉告诉我DP,而且n只有20,估计是状压,因为是博弈,显然是按对角线进行dp的。但是不会表示状态。。。,就放弃去做E了。
做完E,想了半天也没头绪,最后没憋住,看了一下官方题解,居然没看懂。。。跑去看大神的代码,div2居然没人过!!!
又跑去div1看rng58的代码,果然神代码,没看明白什么意思。。。我怀疑是不是我看错题了,但是看了几遍觉得没错。下午问胡大,
胡大说以前做过,也没看明白。。。留着以后再做吧。
----------------------------------------------------------我最后是分割线----------------------------------------
题意
给n个数ai,和k,可以把ai减去不超过k,问所有数最大公约数是多少?
思路
假设最大公约数是d,那么 ai % d <= k。
令 m = min{ai},显然 d <= m
如果 ai % m <= k ,那么m即所求。
a %m <= m-1 , 那么 m-1 <= k 。 所以 当 m <= k+1 时, m即所求。
那么 m > k+1 时了?
因为 d最小只要取k+1,那么肯定满足条件,所以 d 只能取 [k+1,m]之间的数。
枚举d,从m到k+1,检验是不是所有的ai%d <= k 就可以找出d。
但是直接做会TLE(开始就是这么挂掉的。。。)。
我们可以看出 [d,d+k],[2d,2d+k]是不重叠的,所以我们可以统计[d,d+k],[2d,2d+k],...[id,id+k],
i = max{ai}/d。看这些区间一共覆盖了多少个ai,如果是n个的话,那么就一定是解。
所以hash一下,先预处理区间中ai的个数,然后枚举1到i,统计一下就可以了(自己脑子抽了一下,想了半天才想到hash,果然是老了)。
题意
坐巴士和电车,有4种票
1 单程票,只能坐某个车1次
2 单车票,可以坐某个车无限次次
3 单类票,可以坐所有的巴士或者所有的电车无限次次
4 全票,可以无限制坐无限次。
给你要坐的巴士和电车的线路和次数,问你最小花费。
思路
简单贪心。
首先全票肯定可以全部搞定。
针对某一类,最多是一张单类票。
对于某一单类的每个线路,贪心计算,如果单程票*次数 > 单车票,那就选单车票,否则选单程票。
最后看这个价格是否超过单类票,取小的。
两类的最小花费之和如果小于全票,那就取这个花费即可。
代码写的比较挫,c+v了一下。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<n;i++)
#define FD(i,n) for(i=n-1;i>=0;i--)
#define EPS 1e-8
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;
#define N 1000
int main(){
int ans,s1,s2,n,m,i,j,a,b,c,d,t;
cin >> a >> b >> c >> d;
cin >> n >> m;
ans = d;
s1 = 0;
FU(i,n){
cin >> t;
if(t*a > b) s1 += b;
else s1 += t*a;
}
if(s1 > c) s1 = c;
s2 = 0;
FU(i,m){
cin >> t;
if(t*a > b) s2 += b;
else s2 += t*a;
}
if(s2 > c) s2 = c;
if(ans > s1+s2) ans = s1+s2;
cout << ans << endl;
return 0;
}
----------------------------------------------------------我仍然是分割线-------------------------------------
C.
题意
给你一排N个物品组成的双端队列,机器人去取,单位耗费从左取的是L,从右取是R。
如果连续从左取,附加耗费是 QL;连续从右取,附加耗费是QR。
问你取完的最小耗费。
思路
首先和括号匹配一样,不会出现RL这种取法,所以一定是从某一点分开,左边的全部从左取,
右边的全部从右取。显然交替取的代价比连续取低,所以某一点分开,基础代价是
左边重量和*L+右边重量和*R ,
额外的耗费,令 t = 右边次数 - 左边次数。
如果t > 1 ,那么加上 (t-1) * QR;
如果t< -1 那么加上 (-t-1) * QL。
综上,预处理左边重量累加和和右边重量累积和,然后扫一遍,计算每个分割点的搬运代价,
取极小即可。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<n;i++)
#define FD(i,n) for(i=n-1;i>=0;i--)
#define EPS 1e-8
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;
#define N 100011
int a[N];
int Left[N];
int Right[N];
const int INF = 0x3f3f3f3f;
int main(){
int i,j,n,L,R,QL,QR,s=0,k;
int t,ans = INF;
//freopen("355c.in","r",stdin);
cin >> n >> L >> R >> QL >> QR;
for(i=1;i<=n;i++) cin >> a[i];
for(i=1;i<=n;i++) Left[i] = Left[i-1] + a[i];
for(i=n-1;i>=0;i--) Right[i] = Right[i+1] + a[i+1];
for(i=0;i<=n;i++) {
t = Left[i] * L + Right[i]*R;
k = n - i*2;
if(k>1) t += QR*(k-1);
else if(k<-1) t += QL*(-k-1);
if(t < ans) ans = t;
}
//FU(i,n+1) cout << Left[i] << ',';
//cout << endl;
//FU(i,n+1) cout << Right[i] << ',';
//cout << endl;
cout << ans << endl;
return 0;
}
奇怪的是,我的INF设成0x33333333居然会WA,设成0x3f3f3f3f就AC了。而我拿那个WA的数据本地跑
又不会WA。。。不知道为什么

----------------------------------------------------------我继续是分割线---------------------------------------
D.
题意
一个n*n(n<=20)的矩阵,每个元素是一个小写英文字母,从左上到右下,只能向下和向右走,每次走一步。
两人聪明人轮流走,其路径构成的字符串中如果字符a多,那么第一个人赢;
如果字符b多,那么第二人赢;相同则平局。问最后的结果。
思路
直觉告诉我DP,而且n只有20,估计是状压,因为是博弈,显然是按对角线进行dp的。但是不会表示状态。。。,就放弃去做E了。
做完E,想了半天也没头绪,最后没憋住,看了一下官方题解,居然没看懂。。。跑去看大神的代码,div2居然没人过!!!
又跑去div1看rng58的代码,果然神代码,没看明白什么意思。。。我怀疑是不是我看错题了,但是看了几遍觉得没错。下午问胡大,
胡大说以前做过,也没看明白。。。留着以后再做吧。
----------------------------------------------------------我最后是分割线----------------------------------------
题意
给n个数ai,和k,可以把ai减去不超过k,问所有数最大公约数是多少?
思路
假设最大公约数是d,那么 ai % d <= k。
令 m = min{ai},显然 d <= m
如果 ai % m <= k ,那么m即所求。
a %m <= m-1 , 那么 m-1 <= k 。 所以 当 m <= k+1 时, m即所求。
那么 m > k+1 时了?
因为 d最小只要取k+1,那么肯定满足条件,所以 d 只能取 [k+1,m]之间的数。
枚举d,从m到k+1,检验是不是所有的ai%d <= k 就可以找出d。
但是直接做会TLE(开始就是这么挂掉的。。。)。
我们可以看出 [d,d+k],[2d,2d+k]是不重叠的,所以我们可以统计[d,d+k],[2d,2d+k],...[id,id+k],
i = max{ai}/d。看这些区间一共覆盖了多少个ai,如果是n个的话,那么就一定是解。
所以hash一下,先预处理区间中ai的个数,然后枚举1到i,统计一下就可以了(自己脑子抽了一下,想了半天才想到hash,果然是老了)。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<(n);i++)
#define FD(i,n) for(i=(n)-1;i>=0;i--)
const double EPS = 1e-8;
const int INF = 0x3f3f3f3f;
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 2e6+2;
int a[N];
int main(){
ios::sync_with_stdio(false);
int n,k,d,min=INF,max=0,i,j,c,t;
cin >> n >> k;
FU(i,n){
cin >> t;
a[t]++;
if(t>max) max = t;
if(t<min) min = t;
}
if(min <= k+1) {
cout << min << endl;
return 0;
}
for(i=1;i<N;i++) a[i] += a[i-1];
for(d=min;d>=k+1;d--){
c = 0;
for(i=1;i<=max/d;i++) c += a[i*d+k] - a[i*d - 1];
if(c == n) {
cout << d << endl;
return 0;
}
}
return 0;
}