嗯,我又来水codeforces了
A. Cashier
很简单,从头到尾读入客人到达的时间,然后跟上一个客人服务结束时间进行求差,然后除以吸烟时间即可(嗯,补一句,吸烟有害健康)。注意处理初始状态和结束状态即可。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define MAXN 200005 //2e5
//#define TESTING
#ifdef TESTING
#define DEBUG(S, args...) {printf(S, args);printf("\n");}
#else
#define DEBUG(S, args...)
#endif
int main()
{
int n,a,L;
cin >> n >> L >> a;
int cost[MAXN][2];
for (int i = 0; i < n; ++i) {
scanf("%d %d", &cost[i][0], &cost[i][1]);
}
int lastServe = 0;
int ans = 0;
for (int i = 0; i < n; ++i) {
int delta = cost[i][0] - lastServe;
ans += delta / a;
lastServe = cost[i][0] + cost[i][1];
DEBUG("last server time :%d", lastServe);
DEBUG("ans:%d", ans);
}
int delta = L - lastServe;
ans += delta / a;
printf("%d", ans);
return 0;
}
B. Forgery
其实题目挺蛋疼的,说的不清楚,补充了几个说明。大致就是有一个可以写一个3*3方块的笔,这个笔不能写到纸外面,也不能写中间那个格子。而且这个笔必须每次都写3*3的格子。。。。嗯,这个笔跟我们的画风不一样。。。。直接暴力搜所有接空间即可,针对所有需要有笔迹的地方,枚举是否可以用这个笔写满。已经写过的格子可以不枚举。每次枚举需要把八个格子作为起始点进行枚举。乍看之下是8*8 * 1000 *1000的时间复杂度,担心TLE,但是实际上由于每次写的时候都是写8个格子,之后遇到写过的格子可以不枚举,所以时间复杂度是接近1000 *1000的,所以还是AC了。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define MAXN 200005 //2e5
#define TESTING
#ifdef TESTING
#define DEBUG(S, args...) {printf(S, args);printf("\n");}
#else
#define DEBUG(S, args...)
#endif
int signEmpty[1002][1003];
string sign[1005];
int n,m;
int dir[8][2] = {
{1,1},{1,-1},{1,0},
{0,1},{0,-1},
{-1,-1}, {-1,1},{-1,0}};
bool check_as_central(int x,int y)
{
for (int i = 0; i < 8; ++i) {
if(x+dir[i][0]>=n || x+dir[i][0]<0)return false;
if(y+dir[i][0]>=m || y+dir[i][1]<0)return false;
if(sign[x + dir[i][0]][y+dir[i][1]] == 0)return false;
}
return true;
}
void mark_from_central(int x, int y)
{
for (int i = 0; i < 8; ++i) {
signEmpty[x+dir[i][0]][y+dir[i][1]]=1;
}
}
bool check(int x,int y)
{
for (int i = 0; i < 8; ++i) {
if(check_as_central(x+dir[i][0], y+dir[i][1]))
{
mark_from_central(x+dir[i][0], y+dir[i][1]);
return true;
}
}
return false;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; ++i) {
cin >> sign[i];
}
for(int i = 0 ;i < n; ++i)
{
for (int j = 0; j < m; ++j) {
if(sign[i][j] == '.')sign[i][j] = 0;
else sign[i][j] = 1;
}
}
// for (int i = 0; i < n; ++i) {
// for (int j = 0; j < m; ++j) {
// printf("%d",(int)sign[i][j]);
// }
// printf("\n");
// }
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if(sign[i][j] == 0) continue;
if(signEmpty[i][j]==1)continue;
if(!check(i,j))
{
printf("No\n");
return 0;
}
}
}
printf("Yes\n");
return 0;
}
C. Sequence Transformation
题目要求给出一个n,然后这个n构造一个1,2,3,4.。。。。n-1,n的n个数的数列,针对这个数列,进行n次操作,每次都是先算一个剩余全体数字的gcd,然后去除原数列里面的一个数字。每次操作得到的gcd,构造成一个序列,求怎么进行删除操作,可以构造一个字典序最大的序列。
首先,对于一个队列,如果里面有两个互质的数,那么不管这个队列有多少数字,他们的gcd总是1。
然后,不考虑更复杂的情况,只考虑简单的情况。我们看这个要怎么处理。由于队列里有互质的数字的时候,gcd总是1,两个质数总是互质,我们最先要考虑的就是怎么移除质数。以n=6为例子。1 2 3 4 5 6,如何构造字典序列最大呢?1 2 3 5这几个质数,肯定是要先去掉的,否则gcd总是1,去除1 5 都没问题,但是2和3,去除哪个呢?很明显,去除3比较合适,因为去除三之后,剩下2 4 6,可以有gcd 2。之后去除2 4,就有gcd 6了,于是有
1 1 1 2 2 6 的队列。
如果第三步那里去除2,就需要在第四步才能构造一个非1的gcd。
另外,更有趣的事情是,2 4 6,这三个数,在除以gcd 2之后,变成了1 2 3,所以这三个数的处理策略,跟处理1 2 3是一样的。
那么这个策略如何概括呢?答案就是计算最小质因子出现次数。
1,我们对前n个数,计算他们的最小质因子出现的次数分别是多少,对于i<=n,记录出现次数最多的质因子,如果出现次数相同,则记录最大的质因子。
2,对于前n个数字,我们看前n个最小质因子出现次数最多的是哪个质因子。我们可以断定,这个质因子x,就是我们当前最快能得到的非1 gcd,只需要移除没有这个质因子的数字就行了。
3,移除这些没有质因子x的数字的过程中,我们的gcd总是1,直到这些数字被移除,我们的gcd才变成x。
4,移除之后,我们将当前数字,更新为质因子x出现的次数,就是下一个队列需要处理的n,从第一步开始重复,只不过得到的结果要乘以x。
5,重复直到n为1。
我们再回过头来看n=6的情况:
1,从1到6,出现最多的质因子是2,出现了3次,(2,4,6)。然后是3,出现了一次(3)(注意,我们只计算最小质因子)。
2,所以我们得出前面3个gcd必定是1,有了队列1 1 1。然后从第四个开始,gcd为2。
3,我们把gcd 2记下来,2 4 6 退化成1 2 3。这里质因子出现的次数相同,都是1次,这个时候最大的质因子是3。
4,所以我们前面2个gcd必定是1,然后第三个gcd为3。所以1 2 3的处理结果为 1 1,这里1要跟前面的gcd 2相乘,所以有1 1 1 2 2
5,把gcd 3 记下来,3 退化成1,gcd肯定为1,这里要跟前面的2和3 相乘,得到最后的队列1 1 1 2 2 6
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define MAXN 200005 //2e5
//#define TESTING
#ifdef TESTING
#define DEBUG(S, args...) {printf(S, args);printf("\n");}
#else
#define DEBUG(S, args...)
#endif
#define MX 1000005
int prime[MX+5], factor[MX+5], input[MAXN],s[MX], ptr = 0;
int maxfactor[MX+5][2];
void init_primes_with_factor(int n)
{
for (int i = 2; i <= n; ++i) {
if(factor[i]== 0)
{
prime[ptr]=i;
factor[i]=prime[ptr];
ptr++;
}
for(int j=0; i*prime[j] <= MX;++j)
{
factor[i*prime[j]] = prime[j];
if(i % prime[j] == 0)break;
}
}
int maxN = 0,maxFactor = 1;
map<int,int> factors;
for (int j = 1; j <= n; ++j) {
factors[factor[j]]++;
if(factors[factor[j]] > maxN )
{
maxFactor = factor[j];
maxN = factors[factor[j]];
}
else if(factors[factor[j]] == maxN && factor[j] > maxFactor)
{
maxFactor = factor[j];
maxN = factors[factor[j]];
}
maxfactor[j][0] = maxFactor;
maxfactor[j][1] = maxN;
}
}
int main()
{
int n = 0;
cin >> n;
factor[1] = 1;
init_primes_with_factor(n);
int ans[n];
int ansPtr = 0;
int baseFactor = 1;
for (int i = n; i > 1; ) {
int maxFactor = maxfactor[i][0];
int maxN = maxfactor[i][1];
for (int j = 0; j < i-maxN; ++j) {
ans[ansPtr] = baseFactor;
DEBUG("ans[%d]:%d",ansPtr, ans[ansPtr]);
ansPtr++;
}
baseFactor *= maxFactor;
i = maxN;
DEBUG("maxFactor:%d, maxN:%d, baseFactor:%d, ansPtr:%d", maxFactor, maxN, baseFactor, ansPtr);
DEBUG("i is %d",i);
}
ans[ansPtr++] = baseFactor;
for (int i = 0; i < n; ++i) {
printf("%d ", ans[i]);
}
printf("\n");
return 0;
}
D. Nature Reserve
总的来说就是计算一个圆,将所有点包括进来,然后还要跟y=0相切。
ok,先来算不可能的情况,很明显,如果有两个点在河的两侧,直接gg。如果y=0上面有两个点,也gg。
然后我们来计算最大的R是多少。很显然,最大的R出现在当几个个动物分别在(-10^7,1)和(10^7, 1)(10^7,10^7),(-10^7,10^7)几个点的时候。这个时候,取x = 0,y=R做圆心,R满足:
R*R = (R-1)^2 + (10^7)^2
解方程得到R=(10^14 + 1) /2
故而这个就是R的上限了。为了方便,我们直接放大一点,将R放到10^16去算。
然后我们用二分查找法,确认R的范围即可。每次取一个R,检查是不是可以做到让所有点都在这个圆里面。
R确定后,可以肯定,点应该取在(x,R),这里只要针对每个点,计算x的取值范围,然后将所有的取值范围进行合并,最终要求合并的结果不为无结果即可。
对于确定了R的情况,一个点(x1,y1)对应的圆心取值x需要满足
R*R = (R-y1)^2 + ( x - x1)^2
用公式求解上方的x得到两个解,就是x的左右边界了。
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
#define MAXN 100005 //2e5
#define TESTING
#ifdef TESTING
#define DEBUG(S, args...) {printf(S, args);printf("\n");}
#else
#define DEBUG(S, args...)
#endif
int n = 0;
int cord[MAXN][2];
int solve_function(long double a, long double b, long double c, long double &x1, long double &x2)
{
int ret = 0;
long double d = b*b - 4*a*c;
if(d < 0) ret = 0;
else if(d == 0)
{
ret = 1;
x1 = x2 = (-b/(2.0*a));
}
else
{
ret = 2;
long double e = sqrt(d);
x1 = (-b + e) / (a * 2.0) ;
x2 = (-b - e) / (a * 2.0) ;
}
return ret;
}
bool check(long double R)
{
long double l = -1e16, r = 1e16;
for (int i = 0; i < n; ++i) {
long double x = cord[i][0], y = cord[i][1];
long double a = 1.0;
long double b = 2.0 * x;
long double c = (x*x + y*y - 2 * y * R);
long double x1,x2;
int ret = solve_function(a,b,c,x1,x2);
if(ret == 0)return false;
if(x1 > x2)
{
long double tmp = x1;
x1 = x2;
x2 = tmp;
}
l = max(l, x1);
r = min(r, x2);
if(l > r)return false;
}
return true;
}
int main()
{
cin >> n;
bool isNegative = false, isPostive = false, isZero = false;
for (int i = 0; i < n; ++i) {
scanf("%d %d", &cord[i][0], &cord[i][1]);
if(cord[i][1] < 0){isNegative = true, cord[i][1] *= -1;}
else if(cord[i][1] > 0) isPostive = true;
else {
if(isZero)
{
printf("-1");
return 0;
}
isZero = true;
}
}
if(isNegative && isPostive)
{
printf("-1");
return 0;
}
long double l = 0, r = 1e16;
for (int i = 0; i < 255; ++i) {
long double mid = (l + r) / 2.0;
if(check(mid))
{
r = mid;
}
else
{
l = mid;
}
}
long double mid = (l + r) / 2;
printf("%Lf", mid);
return 0;
}