CDZSC_2022寒假个人训练赛21级(3)题解

签到题其实是CEF,中等题是ABDH,G 很简单只不过某种意义上很难。
公告也写了,不会就跳,不要在一题上死磕。

A Roman and Browser CodeForces - 1100A

题意

给你一个长度为 n 的由 -1 和 1 组成的数组和间隔距离k,选一个位置 b 每隔 k 个删除一个,问你在不同的初始位置 b 的选择中,最后这个数组的总和的绝对值最大。

题解

模拟,数据范围很小,两个 for 循环,遍历所有结果就好。

AC代码

int s[105];
int main() {
	int n, k,ans=0;
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; i++)
		scanf("%d", s+i);
	for (int i = 0; i < k; i++) {
		int x = 0;
		for (int j = 0; j < n; j++) 
			if ((j - i) % k != 0) 
				x += s[j];
		x = abs(x);
		ans = x > ans ? x : ans;
	}
	printf("%d", abs(ans));
    return 0;
}

B Array Negations Gym - 102152I

题意

题意很简单,给你一个长度为 n 的数组,和变化次数 k 。你要对数组进行 k 次操作,每一次操作是选择一个数字将它取反。
要注意的是,同一个数可以取反多次,比如 1 我取反2次,它还是1。

题解

  • 方法一
    • 贪心、小根堆
    • 思路上很简单就只要把最小的那个数字一直取反就好了,如果那个数字是负数,则会增加总和,如果是零则不影响,如果是正数,那说明目前没有负数和零了,那把它取反对目前的影响也是最小的。
      比如:-1,0,1,2 ,k为7。
      首先取反-1,变为0,1,1,2,然后0一直是最小,一直取反0不变。
      比如:-1,1,2,k为7。
      第一次: 1,1,2
      第二次: -1,1,2
      以此反复
    • 实现方法使用的是小根堆(优先队列),它可以在复杂度为O(logn)进行一次插入或删除操作来维护一个有序组,c++ std有直接的实现,可以拿来用,具体看下面代码。
  • 方法二
    • 贪心
    • 这个方法就是纯贪心,只不过比较麻烦,细节比较多,具体就不多讲了,自己体会下。
      设数组的负数个数为a,数组为s。
      首先对所给的数组排序,之后按一下条件处理。
      • if (k<=a or s中存在0 or (k-a)%2==0 )
        • 从小到大将 min(k,a) 个负数都改为正数,
      • elif ((k-a)%2==1)
        • 比较最小的正数和最大的负数的绝对值,哪个小就把那个变为负数。
          elif (k>n)
        • 最后判断一次k-n的奇偶性,偶数不变,奇数,将最大的负数变回去。
  • 方法三
    • 贪心
    • 此方法由王璐聃同志提供
    • 排序后从小到大将负的改正,改完所有负数后,如果剩下次数为奇数并且没有零,那将改完的其中最小的再改一次

AC代码

  •  //方法一
     priority_queue<int, vector<int>, greater<int> > q;
     int main() {
     	int t;
     	scanf("%d", &t);
     	while (t--) {
     		int n, k, sum = 0;
     		scanf("%d%d", &n, &k);
     		for (int i = 0; i < n; i++) {
     			int x;
     			scanf("%d", &x);
     			q.push(x);
     		}
     		for (int i = 0; i < k; i++) {
     			int x = q.top();
     			q.pop();
     			q.push(-x);
     		}
     		for (int i = 0; i < n; i++) {
     			sum += q.top();
     			q.pop();
     		}
    
     		printf("%d\n", sum);
     	}
     return 0;
     }
    
  •   //方法二
      int s[10004];
      int main() {
      	int t, n, k;
      	scanf("%d", &t);
      	while (t--) {
      		scanf("%d%d", &n,&k);
      		for (int i = 0; i < n; i++) {
      			scanf("%d", s + i);
      		}
      		sort(s, s + n);
      		for (int i = 0; i < k; i++) {
      			if (i >= n) {
      				if ((k - i) % 2) {
      					s[i - 1] = -s[i - 1];
      				}
      			}
      			if (s[i] < 0) {
      				s[i] = -s[i];
      			}
      			else {
      				if(s[i]&&(k - i) % 2){
      					if (i&&s[i - 1] < s[i]) {
      						s[i - 1] = -s[i - 1];
      					}
      					else {
      						s[i] = -s[i];
      					}
    
      				}
      				break;
      			}
    
      		}
      		int sum = 0;
      		for (int i = 0; i < n; i++) {
      			sum += s[i];
      		}
      		printf("%d\n", sum);
      	}
      return 0;
      }
    
    
  •   //方法三
      #include<bitsdc++.h>
      using namespace std;
      int t, a[10010];
      int main() {
          scanf("%d", &t);
          while (t--) {
              int n, k;
              scanf("%d%d", &n, &k);
              int sum = 0;
              int flag = 0;
              for (int i = 0; i < n; i++) {
                  scanf("%d", &a[i]);
                  sum += a[i];
              }
              sort(a, a + n);
              int ff = 0;
              for (; a[ff] < 0 && k > 0 && ff < n; k--) {
                  sum = sum - 2 * a[ff];
                  a[ff] = -a[ff];
                  ff++;
              }
              sort(a, a + n);
              sum = sum - 2 * (k % 2 * a[0]);
              printf("%d\n", sum);
          }
          return 0;
      }
    
    

C Yet Another Two Integers Problem CodeForces - 1409A

题意

给你两个数a、b,你一次操作可以给a加上-10~10的值,问你最少加几次能把a变成b

题解

贪心
用除法和取模来优化一次一次加减。
答案为 a 与 b 的差值除10,有余数则加1

AC代码

int main() {
	int t, a, b;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &a, &b);
        int c = abs(a - b);
		int ans = c / 10;
		if (c % 10 != 0)ans++;
		printf("%d\n", ans);
        //printf("%d\n", abs(a - b) / 10 + (abs(a - b) % 10 != 0));
	}
	return 0;
}

D Ping-pong CodeForces - 1455C

题意

两人打球,发球和接球都消耗一体力,给你体力a,b。a先手,问在两个人都最优策略下,优先最大化自己的胜利次数,最小化对手的胜利次数,两人的胜利次数。

题解

博弈
关键点是优先最大化自己的胜利次数。
后手若一直让球直到对方最后一个球发出来时再开始接球,则能满足自己胜场最多,对方胜场最少,而先手因为要先发球,所以本质上完全被后手所主导,自己毫无决策空间。

AC代码

int main() {
	int  t, a, b;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &a, &b);
		printf("%d %d\n", a - 1, b);
	}

	return 0;
}

E Dislike of Threes CodeForces - 1560A

题意

给你一个数字k,问你第k个不被3整除并且十进制末尾表示没有3的数是什么。

题解

简单题,打个表筛选下,不被3整除并且十进制末尾表示没有3的数就好,数据范围很小,t*k,才1e5,甚至不用打表,直接遍历整数就好

AC代码

int s[3333];
int main() {
	int t, k;
	scanf("%d", &t);
	int cnt = 1;
	for (int i = 1; i < 3333; i++) {
		if (i % 3 != 0 && i % 10 != 3) {
			s[cnt++] = i;
		}
	}
	while (t--) {
		scanf("%d", &k);
		printf("%d\n", s[k]);
	}
    return 0;
}

F Book Reading CodeForces - 884A

题意

给你天数和阅读需要时间和每一天的工作时间,问你多久可以读完书

题解

模拟

AC代码


int main()
{
	int day = 0,t_day=0;
	int n_time = 0 ;
	int r_time=0,s_time=0;
	int i = 0, j = 0;

	scanf("%d%d", &day, &n_time);
	for (i = 0; i < day; i++){
		scanf("%d", &r_time);
		s_time += (86400 - r_time);
		if (s_time >= n_time){
			t_day = i + 1;
			break;
		}
			
	}
	printf("%d", t_day);
	return 0;
}

G 元素周期表 Gym - 102426D

题意

给你简单化学式,求分子质量。

题解

大大大大模拟。由王璐聃同志强烈推荐,不得已加入。

AC代码

double l[] ={
1.008,
4.003,
6.941,
9.012,
10.81,
12.01,
14.01,
16,
19,
20.18,
22.99,
24.31,
26.98,
28.09,
30.97,
32.07,
35.45,
39.95,
39.10,
40.08,
44.96,
47.88,
50.94,
52,
54.94,
55.85,
58.93,
58.69,
63.55,
65.39,
69.72,
72.59,
74.92,
78.96,
79.90,
83.80,
85.47,
87.62,
88.91,
91.22,
92.91,
95.94,
97.91,
101.1,
102.9,
106.4,
107.9,
112.4,
114.8,
118.7,
121.8,
127.6,
126.9,
131.3,
132.9,
137.3,
138.9,
140.1,
140.9,
144.2,
144.9,
150.4,
152,
157.3,
158.9,
162.5,
164.9,
167.3,
168.9,
173,
175,
178.5,
180.9,
183.9,
186.2,
190.2,
192.2,
195.1,
197,
200.6,
204.4,
207.2,
209,
209,
210,
222,
223,
226,
227,
232,
231,
238,
237.1,
244.1,
243.1,
247.1,
247.1,
252.1,
252.1,
257.1,
258.1,
259.1,
262.1,
265.1,
268.1,
271.1,
270.1,
277.2,
276.2,
281.2,
280.2,
285.2,
284.2,
289.2,
288.2,
293.2,
294.2,
294.2
};
string s[] = {
	"H",
	"He",
	"Li",
	"Be",
	"B",
	"C",
	"N",
	"O",
	"F",
	"Ne",
	"Na",
	"Mg",
	"Al",
	"Si",
	"P"	,
	"S",
	"Cl",
	"Ar",
	"K",
	"Ca",
	"Sc",
	"Ti",
	"V",
	"Cr",
	"Mn",
	"Fe",
	"Co",
	"Ni",
	"Cu",
	"Zn",
	"Ga",
	"Ge",
	"As",
	"Se",
	"Br",
	"Kr",
	"Rb",
	"Sr",
	"Y",
	"Zr",
	"Nb",
	"Mo",
	"Tc",
	"Ru",
	"Rh",
	"Pd",
	"Ag",
	"Cd",
	"In",
	"Sn",
	"Sb",
	"Te",
	"I",
	"Xe",
	"Cs",
	"Ba",
	"La",
	"Ce",
	"Pr",
	"Nd",
	"Pm",
	"Sm",
	"Eu",
	"Gd",
	"Tb",
	"Dy",
	"Ho",
	"Er",
	"Tm",
	"Yb",
	"Lu",
	"Hf",
	"Ta",
	"W",
	"Re",
	"Os",
	"Ir",
	"Pt",
	"Au",
	"Hg",
	"Tl",
	"Pb",
	"Bi",
	"Po",
	"At",
	"Rn",
	"Fr",
	"Ra",
	"Ac",
	"Th",
	"Pa",
	"U",
	"Np",
	"Pu",
	"Am",
	"Cm",
	"Bk",
	"Cf",
	"Es",
	"Fm",
	"Md",
	"No",
	"Lr",
	"Rf",
	"Db",
	"Sg",
	"Bh",
	"Hs",
	"Mt",
	"Ds",
	"Rg",
	"Cn",
	"Nh",
	"Fl",
	"Mc",
	"Lv",
	"Ts",
	"Og"
};

map<string, double> m;
int main() {
	for (int i = 0; i < 118; i++)
		m[s[i]] = l[i];
	int n;
	double sum;
	string c;
	string x;
	string nb;
	scanf("%d", &n);
	while (n--) {
		sum = 0;
		cin >> c;
		int len = c.size();
		for (int i = 0; i < len; i++) {
			if (isupper(c[i])) {
				x = c[i];
				if (islower(c[i + 1])) 
					x += c[++i];
				while (isdigit(c[i + 1]) ){
					nb += c[i + 1];
					i++;
				}
				if (nb.empty())nb += "1";
				sum += stoi(nb)*m[x];
				x.clear();
				nb.clear();
			}
		}
		printf("%.3f\n", sum);

	}




	return 0;
}

H Letters CodeForces - 978C

题意

给出n栋宿舍楼编号为1-n,每栋宿舍楼有ai个宿舍,宿舍编号是从1~a1+a2+...+an,现给出m次查询,每次询问一个编号,问这个编号是第几个宿舍楼的第几个宿舍。m个询问按递增顺序给出。

题解

求出前缀和后二分查找

AC代码

long long h[200010];
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &h[i]);
		h[i] += h[i - 1];
	}
	for (int i = 1; i <= m; i++) {
		long long x;
		int j;
		scanf("%lld", &x);
		j = lower_bound(h,h+n,x)-h;
		printf("%d %lld\n", j, x - h[j-1]);
	}
	return 0;
}
posted @ 2022-01-25 17:02  _comet  阅读(154)  评论(0编辑  收藏  举报