集训队每周一赛 2020-03-26(思维/构造+数学+博弈)


第五次周赛

  • A 天才之战
    • CodeForces 151C
    • 题解
  • B 这是一道数学题
    • CodeForces 1266A
    • 题解
  • C 另一个世界的牛郎织女
    • CodeForces 1304A
    • 题解
  • D 垒骰子
    • CodeForces 1266B
    • 题解
  • E 我是司令官
    • CodeForces 1327C
    • 题解
  • F 小A的购房烦恼
    • CodeForces 1055A
    • 题解

A 天才之战 CodeForces 151C 传送门
总所周知,小云和小吉是天才,因此他们两个很喜欢玩智力游戏。
今天他们决定玩一个关于因数分解的游戏;
规则是这样的:
首先你需要理解什么是独特因子,n的独特因子就是n除去1和n本身的因子,例如6的独特因子只有2,3,而7就不存在独特因子;他们会得到一个数字n,小云写下一个n的独特因子q,然后小吉再写下一个q的独特因子p,小云再去写p的独特因子…如果游戏过程中有人写下了一个不存在独特因子的数p,那么对方就会获胜,特别地当初始值n本来就没有独特因子时,小云会获胜。
已知两人都是绝顶天才,都会以最优的策略去玩这个游戏,小云先手操作,小吉后手操作。给你一个正整数n,请你帮小云判断一下她能否获胜,输出(1or 2),1表示小云能获胜,2表示小云不能获胜;若小云能获胜,请你输出小云第一步应该写哪一个n的独特因子(若n本来就没有独特因子,请输出0)可以使小云最终能获胜,可能有多种方案,你可以输出其中的任意一种;
输入描述:
输入仅1行,为一个正整数n(1 <= n <= 10^13)
输出描述:
当小云能获胜时输出两行,第一行为1,第二行为小云第一次写的数字(当小云第一次就无法写出n的独特因数时,该数字应为0);
当小云不能获胜时输出为一行,第一行为2;
示例:
Input
6
Output
2
Input
30
Output
1
6
Input
1
Output
1
0
题解 3回合内解决,能够一回合赢的,当n是1或者是质数时,先手必赢;能够两回合赢的,当n只能分解成2个质数的乘积时,后手必赢;能够三回合赢的,将n唯一分解, 然后写一个因数使只留下两个质数的乘积给对手,先手必赢。
#include #include using namespace std; typedef long long LL; LL isprime(LL n) { for(int i=2; i<=sqrt(n); i++) { if(n%i == 0) return n / i; } return n; } int main() { LL n; cin >> n; LL tmp1,tmp2; if((tmp1=isprime(n))==n) { cout<<1<

B 这是一道数学题 传送门
CodeForces 1266A
你将得到一个范围为0~10^100(可能包含前置零)的非负整数,请你判断一下能否将这个非负整数重新排列(允许有前置零)后,使重新排列的数是60的倍数
输入描述:
第一行为一正整数T(1 <= T <= 418),为样例数
接下来为n行
每一行都是一个非负整数n(0 <= n <= 10^100),n可能有前置零;
输出描述:
若存在一种方案使得n重新排列后是60的倍数输出 red,否则输出cyan
示例:
Input
6
603
006
205
228
1053
0000000000000000000000000000000000000000000000
Output
red
red
cyan
cyan
cyan
red
题解 如果一个数是60的倍数,那么它是10,2,3的倍数;还要同时是6和10的倍数,所以倒数第二位只能放0,2,4,6,8;既是10的倍数又是2的倍数,最后一位数字只能为0,3的倍数,再判断一下位数和是不是3的倍数。
#include #include void fun(char s[], int l) { int i, sum = 0, cnt0 = 0, cnt2 = 0, cntn0 = 0; for(i=1; i<=l; i++) sum += s[i]-'0'; if(sum%3 != 0) { puts("cyan"); return; } for(i=1; i<=l; i++) { if(s[i] == '0') ++cnt0; else ++cntn0; if((s[i] - '0') % 2 == 0) ++cnt2; } if(cntn0 == 0) { puts("red"); return; } if(cnt0 == 0) { puts("cyan"); return; } if(cnt2 >= 2) { puts("red"); return; } puts("cyan"); } int main() { char s[1005]; int i, t; scanf("%d",&t); while(t--) { scanf("%s", s+1); int l = strlen(s+1); fun(s,l); } return 0; }

C 另一个世界的牛郎织女 传送门
CodeForces 1304A
在一个奇妙的国家,这个国家的人迈出的步的距离是恒定的,终生不能改变,但每个人的步长不一定相等;
例如若A的步长为a,那么A走一步的距离只能为a,而另外一个B的步长为b,但b不一定等于a;
而在这里也有牛郎织女,已知牛郎的步长为a,织女的步长为b,牛郎一开始在x的位置,织女一开始在y的位置,他们两都朝着彼此的方向走去,且不会停下,问牛郎和织女能在同一点相遇吗?
集训队每周一赛 2020-03-26(思维/构造+数学+博弈)
文章图片

若能请输出他们在几步后相遇,若不能请输出-1;
输入描述:
第一行为一正整数T,(1 <= t <= 1000),代表样例数
以下为T行
每行为四个非负整数x,y,a,b,代表牛郎的初始位置以及步长,织女的初始位置以及步长(0 <= x,y <= 10^9, 1 <= a,b <=10^9)
输出描述:
对于每一个样例,若能在同一个点相遇输出多少步后相遇,否则输出-1;
示例:
Input
5
0 10 2 3
0 10 3 3
900000000 1000000000 1 9999999
1 2 1 1
1 3 1 1
Output
2
-1
10
-1
1
题解 判断abs(x - y) % (a+b) == 0
#include #include int main() { int t,x,y,a,b,temp; scanf("%d",&t); while(t--) { scanf("%d%d%d%d",&x,&y,&a,&b); if(x>y) { temp=x; x=y; y=temp; } if((y-x)%(a+b)==0) printf("%d",(y-x)/(a+b)); else printf("-1"); if(t) printf("\n"); } return 0; }

D 垒骰子 传送门
CodeForces 1266B
你玩过骰子吗,小K就很喜欢玩骰子;已知小K家有足够多的骰子,每一个骰子的平面展开图都是这样的:
集训队每周一赛 2020-03-26(思维/构造+数学+博弈)
文章图片

小K现在想和你玩一个游戏,小K会给你一个正整数x,不限制你使用骰子的个数,你能垒一个骰子塔,让骰子露出的点数之和等于x吗?
注意是露出的面的点数和,例如:
集训队每周一赛 2020-03-26(思维/构造+数学+博弈)
文章图片

上图这个用2颗骰子垒成的骰子塔,只有9个骰子面是露出来,底下的骰子只露出了4个面,而顶部的骰子露出了5个面。
输出描述:
第一行为一正整数T (1 <= T <= 1000),表示小K给你的正整数x的个数;
第二行有T个正整数xi(1 <= xi <= 10^18)
输出描述:
对于每个x作出一次回答,每一个回答独占一行
若你能垒出一个骰子塔露出面点数之和等于x,请输出YES,否则输出NO
示例:
Input
4
29 34 19 38
Output
YES
YES
YES
NO
题解 骰子对立面点数之和都等于7; 利用这一性质,骰子要么露出5面,要么露出4面,判断一下x%14 <= 6,特判只有一个骰子时,14*3 - i(i = 1,2,…6)
#include #define ll long long int main() { int t; ll n; scanf("%d",&t); while(t--) { scanf("%lld",&n); if(n>14&&n%14>=1&&n%14<=6) printf("YES"); else printf("NO"); if(t) printf("\n"); } return 0; }

E 我是司令官 CodeForces 1327C 传送门
在一个n* m的网格图里面,有k个士兵以及k个扎营地,每一个士兵和扎营地
都位于一个格子里面;
现在这k名士兵需要到每一个扎营地去报到,但是这些士兵只听从你的命令,
你的命令有以下几种:
L:若士兵在(x , y)会去到(x, y - 1);
R: 若士兵在(x , y)会去到(x, y + 1);
D: 若士兵在(x , y)会去到(x + 1, y);
U:若士兵在(x , y)会去到(x - 1, y);
你的命令只能对所有士兵发起,即你传达了L命令则所有士兵都会执行L命令,
但如果有士兵执行这条命令后会走出网格图,这名士兵就会待在原地不动;
你能传达不多于2 * n * m条命令使得每一名士兵都到k个扎营地报到吗?若能
请按顺序输出你的命令,若不能请输出-1;
(可能存在多名士兵在一个格子或者多个扎营地在同一格子,当士兵原来所处位置就有一个扎营地时,该名士兵不再需要到这个营地报到。
注意:你不需要让命令的数量最少,只需要是不多于2* n * m条命令,且让k名士兵都到达过k个扎营地,这个方案就可以作为答案,可行的方案可能多种,你只需要输出其中一种即可)
输入描述:
第一行有三个正整数n,m,k,分别表示网格图大小为n * m的,有k名士兵以及k个扎营地
以下有2* k行,第2 ~ k+1行描述的是士兵的位置,第k+2 ~ 2* k+1行描述的
是扎营地的位置;
对于位置的描述为两个整数 x,y,表示该士兵/扎营地在(x , y)的位置上;
输出描述:
若能完成题目要求输出你的命令的条数以及你的命令,若不能找到一个可行方
案满足题目要求请输出-1
示例:
Input
3 3 2
1 2
2 1
3 3
3 2
Output
3
DRD
Input
5 4 3
3 4
3 1
3 3
5 3
1 3
1 4
Output
9
DDLUUUURR
题解 将所有点移动左上角的那个点,再遍历整个图。
#include int main() { int n,m,k,i,j; int a[250],b[250],x[250],y[250]; scanf("%d%d%d",&n,&m,&k); for(i=0; i

F 小A的购房烦恼 CodeForces 1055A 传送门
小A工作的城市只有两条地铁且这两条地铁的路线是一样的只是方向不同:
一条是从1站点出发到达n站点(1 -> 2 -> 3 -> 4 ->…->n),
一条是从n站点出发到达1站点(n -> n-1 -> … -> 1);
但是两条地铁不是每个站点都停靠,两条地铁停靠的站点也不一定相同。当两条地铁都停靠在同一个站点时,才可以换乘地铁;
已知小A上班的公司在站点 s 附近,而站点 1 附近有许多廉价的出租房,但小A想自己住的地方可以只通过乘坐地铁到达公司;
给你两条地铁
停靠站点的信息,请你帮小A判断是否应该在站点1附近租房
输入描述:
输入有三行:
第一行为两个正整数n,s;表示这座城市有n个站点,s表示小A的公司在s附近
第二行是长度为n的数组ai :a1 a2 … an(ai等于0或1),当ai为1时表示从1站点开往n站点的地铁在i站点停靠,否则不停靠;
第三行是长度为n的数组bi :b1 b2 … bn(bi等于0或1),当bi为1时表示从n站点开往1站点的地铁在i站点停靠,否则不停靠;
输出描述:
输出一行YES或者NO,YES表示小A可以在站点1附近租房,NO为不可以
示例:
Input
5 3
1 1 1 1 1
1 1 1 1 1
Output
YES
Input
5 4
1 0 0 0 1
0 1 1 1 1
Output
YES
Input
5 2
0 1 1 1 1
1 1 1 1 1
Output
NO
题解 【集训队每周一赛 2020-03-26(思维/构造+数学+博弈)】先考虑NO的情况:a1 != 1上不了车,as!=1&&bs!= 1下不了车;其次当不满足NO条件后,若as == 1,一定YES; 若要换乘必须有两地铁同时停靠的站点,且该换乘站必须>s(若需通过换乘说明只能通过第二条地铁到达s站点)
#include int main() { int i,n,s,a[1005],b[1005]; scanf("%d%d",&n,&s); for(i=1; i<=n; i++) scanf("%d",&a[i]); for(i=1; i<=n; i++) scanf("%d",&b[i]); if(a[1]==0||(a[s]==0&&b[s]==0)) { printf("NO"); return 0; } else if(a[s]==1) { printf("YES"); return 0; } else { for(i=s+1; i<=n; i++) { if(a[i]==1&&b[i]==1) { printf("YES"); return 0; } } } printf("NO"); return 0; }

    推荐阅读