CodeforcesRound#549(Div. 2)(A-D题解)

http://codeforces.com/problemset/problem/1143/A

题意:给你一串01代表n个按钮(0是一种,1是一种),如果同种按钮都按过了,你就能逃生,但你必须从头开始按按钮。问你逃生前按下的最后一个按钮标号。

思路:从最后一个开始,如果有一个按钮跟最后一个按钮不同,输出标号即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int a[200005];
 5 int main() {
 6     int n;
 7     cin >> n;
 8     for(int i = 1;i <= n;i ++){
 9         cin >> a[i];
10     }
11     int t = a[n];
12     for(int i = n;i >= 1;i --){
13         if(a[i] != t){
14             cout << i << endl;
15             break;
16         }
17     }
18 
19     return 0;
20 }
A

 

 

http://codeforces.com/problemset/problem/1143/B

题意:求出1到n的所有数的最大数位积(每一位相乘的结果)。

思路:可以模拟来求,代码量可能会大一点,但是此处可用记忆化搜索。

   令表达式 Dgt(n) 代表 n 的数位积:

    如果想让 Dgt(n) 最大,那么必须满足以下两点:

      1、Dgt(n/10) * (n%10) 最大;

      2、Dgt(n/10 - 1) * 9 最大。(比如258,那么某个接近他的理想状态应该是249,968则是959,因为要保证9的数量)

    所以只需要对上述两种情况求max值。

   这个代码竟然卡了我好久,看来是菜了不少啊。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int solve(int x){
 5     if(x == 0){return 1;}
 6     if(x < 10){return x;}
 7     int t1 = (x % 10) * solve(x / 10);
 8     int t2 = 9 * solve((x / 10) - 1);
 9     return max(t1,t2);
10 }
11 
12 
13 int main(){
14     int n;
15     cin >> n;
16     cout << solve(n) << endl;
17 
18     return 0;
19 }
B

 

 

http://codeforces.com/problemset/problem/1143/C

题意:给一个有根树,如果一个点被标记了1,并且这个点所有儿子也都是1,那么这个点可以被删去,并且这个点的所有儿子会连接到它的父亲身上。

   如果有点能删,那么就删掉,如果同时出现多个点可删,那么删掉最小标号的点。

   一直删到没有任何点可以删去,那么就结束。

   按顺序输出删点过程,初始则是无点可删树,则输出-1。

思路:仔细想想。。。这个破树在删点过程中完全不会出现逆序。一定是先删序号小的点,再删序号大的点。

   暴力跑一遍即可。

   这破玩应我也证明了一会。。。好像傻。。。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 vector<int> V[100005];
 5 int R[100005];
 6 int C[100005];
 7 int main(){
 8     int n;
 9     cin >> n;
10     memset(R,0,sizeof(R));
11     memset(C,0,sizeof(C));
12     for(int i = 1;i <= n;i ++){
13         int t1,t2;
14         cin >> t1 >> t2;
15         if(t1 != -1){V[t1].push_back(i);}
16         R[i] = t2;
17     }
18     for(int i = 1;i <= n;i ++){
19         int CD = 1;
20         for(int j = 0;j < V[i].size();j ++){
21             if(R[V[i][j]] == 0){CD = 0;break;}
22         }
23         C[i] = CD;
24     }
25     int f = 1;
26     for(int i = 1;i <= n;i ++){
27         if(C[i] && R[i]){cout << i << " ";f = 0;}
28     }
29     if(f){cout << "-1" << endl;}
30 
31     return 0;
32 }
C

 

 

http://codeforces.com/problemset/problem/1142/A

题意:题面十分缺德,大概翻译一下:

   有一个环,大小是 n*k (n 和 k 已知),有一个人在未知起点 S 开始走,未知步长为 L。

   在这个环上,有k个饭店,分别在 1,(1+k),(1+2k)......

      经过未知步数后这个人会走回 S,此时结束。

   你还知道两个常数 a 和 b。a 代表你的初始位置和初始位置最近的饭店距离,b 代表你走过一步之后的位置和当前位置最近的饭店距离。

   求最小可能步数以及最大可能步数。

思路:黑色点是饭店,白色点没有东西,绿色点是起点,红色点是从起点走过一步之后的位置

   设步行次数为 ans ;n,a,b,L,k 均为题意所给含义,则有:

    ans * L = n * k * x (x为某个常数,未知量);

    (±a ±b) + y * k = L (y为某个常数,未知量,(±a ±b)代表4个不同的表达式,所有情况都取到);

    gcd(ans,x) == 1。

    可根据L联立两个等式:(n * k * x) / ans = (±a ±b) - y * k 。

    这样我们发现,右侧的部分是可以使用 y 进行枚举的,而且 y 的极值不会超过 n 。

    那么 L 就等于  (±a ±b) - i * k,(此时 i 为枚举值)

    整理:L * ans = (n * k) * x 。

    此时,只有 x 和 ans 是未知的了,但是前面给出了 gcd(ans,x) == 1。

    那么我们可以让 G = gcd(n * k,L),再将 L 和 n * k 分别除以 G 。

    这样出现了 gcd(n * k / G,L / G) == 1 。

    那么就形成了等式两边出现两对互质的数,那么一定存在 ans = n * k / G 。

   所以这道题,只需要进行枚举四种情况的 1 到 n 即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 long long maxx,minn;
 5 long long n,k,a,b;
 6 
 7 void solve(long long z){
 8     for(long long i = 1;i <= n;i ++){
 9         long long L = k * i + z;
10         long long G = __gcd(n * k,L);
11         long long res = n * k / G;
12         if(res > 0){
13             maxx = max(maxx,res);
14             minn = min(minn,res);
15             //cout << minn << " " << maxx << endl;
16         }
17     }
18 }
19 
20 int main()
21 {
22     maxx = -1;
23     minn = 1000000000000000000;
24     cin >> n >> k >> a >> b;
25         solve(a + b);
26     solve(a - b);
27     solve(b - a);
28     solve(0LL - a - b);
29     cout << minn << " " << maxx << endl;
30 
31     return 0;
32 }
D

 

转载于:https://www.cnblogs.com/love-fromAtoZ/p/10633194.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值