Codeforces Round #694 (Div. 2)ABCDF题解
目录
A. Strange Partition
思路:
最小:n个数先求和,再除以x
最大:n个数先分别除以x,再求和
#include<bits/stdc++.h>
#define LL long long
#define mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Scl(x) scanf("%lld",&x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)
#define fo(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
using namespace std;
template<class T>inline void read(T &x){
x=0;register char c=getchar();register bool f=0;
while(!isdigit(c))f^=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
}
int main(){
int t;
cin>>t;
int n,x,k;
while(t--){
LL sum1=0,sum2=0;
cin>>n>>x;
for(int i=0;i<n;i++){
cin>>k;
if(k%x==0){
sum1+=k/x;
}
else sum1+=k/x+1;
sum2+=k;//最小值
}
if(sum2%x==0)sum2=sum2/x;
else sum2=sum2/x+1;
cout<<sum2<<" "<<sum1<<endl;
}
return 0;
}
B. Strange List
思路:
刚理解错题意了,题目问的是最终数组所有数的和,我理解成了要计算:当 robot停止的时候,robot扫过的数字和,这显然难度太大,因为你要考虑被分解后得到的数最后是否要被计算到sum里,归结原因,还是自己经验太少,英文题意理解的一知半解,甚至样例解释都没看完就去推公式了
正解:插入x个q/x就是加q,只要q能被x整除就加q,一直到出现一个不能被x整除的数为止,就停止,计算技巧: 多设置一个数组b[]存保存初始值a[],初始值a[]不断变化,但sum加的值一直为初始值b[]的值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100010], b[100010];
template<class T>inline void read(T &x){
x=0;register char c=getchar();register bool f=0;
while(!isdigit(c))f^=c=='-',c=getchar();
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(f)x=-x;
}
int main(){
ll t, n, x, i;
read(t);
while (t--){
int flag = 0;
ll sum = 0;
read(n);read(x);
for (i = 0; i < n; i++)
read(a[i]), b[i] = a[i], sum += b[i];
while (1){
for (i = 0; i < n; i++){
if (a[i] % x){
flag = 1;
break;
}
sum += b[i], a[i] /= x;
}
if (flag) break;
}
cout << sum << endl;
}
}
C. Strange Birthday Party
思路:
贪心,注意题干说了c序列升序即可
#include<bits/stdc++.h>
using namespace std;
int k[300010], c[300010];
int main(){
int t, n, m, i, j;cin >> t;
while (t--){
long long sum = 0;
cin >> n >> m;
for (i = 1; i <= n; i++)cin >> k[i];//限定范围
for (i = 1; i <= m; i++)cin >> c[i];//cost
sort(k + 1, k + n + 1);
int pn = 0;//设立一个对c的指针,O(n)扫完
int mi = c[++pn];//最便宜的
for (i = n; i >= 1; i--){//k大的先选
if (mi < c[k[i]]) sum += mi, mi = c[++pn];
else sum += c[k[i]];
}
cout << sum << endl;
}
}
D. Strange Definition
思路:
可以把每个数字归结为某个数字,如果这个数字出现次数是奇数,最后一定是最小的不能除以完全平方数字的数字,如果是偶数,那么最后可以规约为1.然后判断w是否为0输出不同情况即可。
- 如果一个组内元素个数(这个数字出现次数)是偶数,那么经过一秒后,所有这样的小组就可以合成一组。
- 如果组内元素个数是奇数,经过一秒后,它们不会改变,即无法合成一组
1秒及之后的时间情况都是和1秒的时候相同的,答案只要考虑0秒和1秒及之后两种情况。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int const N = 3e5 + 10;
int n, q, T;
unordered_map<int, int> mp;
void solve(int x) {
for (int i = 2;; i++) {
int two = i * i;
while (x % two == 0 && x >= two) x /= two;
if (x < two) break;
}
mp[x]++;
//x的出现次数和是x否是1,是我们关心的重点
}
int main(){
scanf("%d", &T);
while (T--) {
mp.clear();
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int a;
scanf("%d", &a);
solve(a);
}
int ans1 = 0;
int ans2 = 0;
for (auto it = mp.begin(); it !=mp.end();it++){
ans1 = max(ans1, it->second);
//cout << it->first << " " << it->second << endl;
//x出现次数是偶数的这些集合们在>=1s后就会合并到一起
//如果x是1,这些集合也会合并到一起
//这两个判断条件不能分开写,不然会WA
if (it->second % 2 == 0 || it->first == 1) ans2 += it->second;
}
ans2 = max(ans2, ans1);//把奇数部分考虑进去
scanf("%d", &q);
for (int i = 0; i < q; i++) {
LL t;
scanf("%lld", &t);
if (t == 0)
cout << ans1 << endl;
else
cout << ans2 << endl;
}
}
return 0;
}
F. Strange Housing
思路:
可以证明如果图是连通图,那么一定存在一种方法使得所有条件成立。因为如果你使用染色法对特殊点染色,一个点周围如果存在特殊点,那么这个点一定不能是特殊点,然后一定可以将所有的点染色。
判断连通用并查集,染色用dfs,详见代码。
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
vector<int> adj[N];//邻接表
int n, m, vis[N], f[N], col[N];
int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
void dfs(int u, int fa){//dfs染色
vis[u] = 1, col[u] = !col[fa];//首先颜色和父亲不同
for (auto v : adj[u])
//如果我之前访问了这个点,且这个点已经被染色了,那么我肯定和它不同
if (vis[v]) col[u] &= !col[v];
//如果我之没访问这个点,且这个点不是父亲,那么我dfs访问这个点
for (auto v : adj[u])
if (!vis[v] && v != fa)
dfs(v, u);
}
int main() {
int T;
cin >> T;
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {//各种初始化
vis[i] = 0, f[i] = i;
adj[i].clear(), col[i] = 0;
}
int comp = n;
for (int i = 1,u,v; i <= m; i++){
scanf("%d%d", &u, &v);
if (find(u) != find(v)) comp--, f[find(u)] = find(v);//并查集判断连通
adj[u].push_back(v), adj[v].push_back(u);//邻接表建图
}
if (comp != 1) {//如果不连通
puts("NO");
continue;
}
puts("YES");
dfs(1, 0);
int cnt = 0;
vector<int> ans;
for (int i = 1; i <= n; i++)
if (col[i]) ans.push_back(i), cnt++;//找被染色的点
printf("%d\n", cnt);
for (auto v : ans) printf("%d ", v);
puts("");
}
return 0;
}
借鉴好文:

浙公网安备 33010602011771号