CF 871 div.4
A. Love Story(字符串)
题目大意:
每次给出一个字符串 s s s,找出 s s s和"codeforces"不同字符的数量
题解:
遍历字符串计数即可
C++
#include <iostream>
using namespace std;
string ss="codeforces";
void sove(void){
string s;
cin>>s;
int ans=0;
for(int i=0;i<ss.size();i++){
if(s[i]!=ss[i])ans++;
}
cout<<ans<<endl;
}
int main(void){
int t;cin>>t;
while(t--){
sove();
}
return 0;
}
B. Blank Space
题目大意:
给出数组的长度,再给出数组的每个数,算数组中连续0的长度的最大值
题解
遍历计数,取最大值
#include <iostream>
using namespace std;
const int N =100+10;
int a[N];
inline int max(int a,int b){return a>b?a:b;}
void sove(void){
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int ans=0;int all=0;
for(int i=1;i<=n;i++){
if(a[i]==0)all++;
else {
ans=max(ans,all);
all=0;
}
}
ans=max(ans,all);
cout<<ans<<endl;
}
int main(void){
int t;cin>>t;
while(t--){
sove();
}
return 0;
}
C. Mr. Perfectly Fine(贪心)
题意:
有两个技能1,2
给出n组数据,每组数据给出学习代价 m i m_i mi和能否学习的技能 s 1 a n d s 2 s_1 and s_2 s1ands2,如果 s 1 = = 1 s_1==1 s1==1就代表能学习该技能,否则就不能
算出学习两个技能最小代价,如果无法将两个技能都学,输出-1
题解:
分三种情况
11 01 10
计算11的代价,01的代价和10的代价和,取最小值即可。
如果没有出现11且没有同时01和10,则输出-1
#include <iostream>
using namespace std;
const int N =2*2e5+10;
int a[N];
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
void sove(void){
int n;
cin>>n;
int ll=N,o1=N,l0=N;
int flag1=0,flag2=0;
while(n--){
int a;string s;
cin>>a>>s;
if(s=="11")ll=min(ll,a);
else if(s=="01")o1=min(o1,a);
else if(s=="10")l0=min(l0,a);
if(s[0]=='1')flag1=1;
if(s[1]=='1')flag2=1;
}
int ans=ll;
if(o1+l0<ll)ans=o1+l0;
if(!(flag1&&flag2))ans=-1;
cout<<ans<<endl;
}
int main(void){
int t;cin>>t;
while(t--){
sove();
}
return 0;
}
D. Gold Rush(dfs)
题意:
可以将一个数字分为两个数字和,但要满足这两个数字是二倍的关系
给出这个数字和一个测试数字 m m m,如果可以通过多次以上步骤得到 m m m,输出"YES",否则输出"NO"
题解:
因为是要二倍的关系,那么反过来,测试数字 m m m可以变成 m + 2 m m+2m m+2m或者 m + m / 2 m+m/2 m+m/2
也就是说 m + 2 m m+2m m+2m和 m + m / 2 m+m/2 m+m/2通过题目步骤才能得到 m m m
那么以 m m m为中心,在坐标轴获取 3 m 3m 3m和 m + m / 2 m+m/2 m+m/2(因为是整数,需要检查m/2是否为整数),然后再以新数字为中心重复操作,直到找到 m = = n m==n m==n
递归终止条件为 m > n m>n m>n
#include <iostream>
using namespace std;
const int N =2*2e5+10;
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
bool check(int x){return (double )x/2.0==x/2;}
int ans=0;
void dfs(int n,int m){
if(m==n){ans=1;}
if(ans==1)return;
if(3*m<=n)dfs(n,m*3);
if(check(m)&&m+m/2<=n)dfs(n,m+m/2);
}
void sove(void){
int n,m;
cin>>n>>m;
ans=0;
dfs(n,m);
if(ans)cout<<"YES\n";
else cout<<"NO\n";
}
int main(void){
int t;cin>>t;
while(t--){
sove();
}
return 0;
}
E. The Lakes(dfs / dsu)
题意:
给出n*m的数组,0表示陆地,大于0的数字表示水深度,湖泊的深度为全部水深之和,如果被边界和陆地隔开的算不同湖泊
问地图中湖泊的最大深度为多少
题解:
经典海路问题,记录非0的数字下标,每次展开dfs,将dfs走过的数字加起来得到一个“准答案”,取准答案最大值即可
#include <iostream>
#include <queue>
using namespace std;
const int N =1010;
struct node{
int x,y;
};
int a[N][N];
bool vis[N][N];
int zou[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int n,m;
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
inline bool check(int x,int y){
return (x<=n&&x>=1&&y>=1&&y<=m&&!vis[x][y]&&a[x][y]!=0);
}
int all=0;
void dfs(int x,int y){
if(check(x,y)){
all+=a[x][y];
vis[x][y]=true;
for(int i=0;i<4;i++)dfs(x+zou[i][0],y+zou[i][1]);
}
}
void sove(void){
cin>>n>>m;
queue<node>q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
{
vis[i][j]=false;//init
cin>>a[i][j];
if(a[i][j])q.push({i,j});
}
}
int ans=0;
while(!q.empty()){
all=0;
dfs(q.front().x,q.front().y);
ans=max(ans,all);
q.pop();
}
cout<<ans<<endl;
}
int main(void){
int t;cin>>t;
while(t--){
sove();
}
return 0;
}
并查集题解:
hetanhnandre’s code
/*
Compete against Yourself.
Author - Hetan Hemant Nandre (@hetanhnandre)
*/
// #pragma GCC optimize("Ofast")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,fma")
// #pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
//Hetan Nandre's code
// Aliases
using ll = long long;
using ull = unsigned long long;
using ld = long double;
// Constants
#define INF 2147483647
#define EPS 1e-9
#define MOD 1000000007
// Macros
#define all(x) begin(x), end(x)
#define allr(x) rbegin(x), rend(x)
#define pb push_back
#define MAX 1e18
#define new "\n"
#define in(a) for(auto &i:a) cin>>i
#define MP make_pair
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repr(i,s,e) for(int i=s;i>=e;i--)
typedef vector<int>vi;
class DSU {
vector<int> parent;
vector<int> size;
public:
DSU(int n) {
parent.resize(n);
size.resize(n, 1);
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
int find(int x) {
if (x == parent[x]) {
return x;
}
parent[x] = find(parent[x]);
return parent[x];
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x != y) {
if (size[x] < size[y]) {
swap(x, y);
}
parent[y] = x;
size[x] += size[y];
}
}
int getSize(int x) {
return size[find(x)];
}
};
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int>> a(n, vector<int>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> a[i][j];
}
}
vector<pair<int, int>> dir = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
DSU dsu(n * m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == 0) {
continue;
}
for (const auto& d : dir) {
int x = i + d.first;
int y = j + d.second;
if (x >= 0 && x < n && y >= 0 && y < m && a[x][y] != 0) {
dsu.unite(i * m + j, x * m + y);
}
}
}
}
unordered_map<int, int> mp;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == 0) {
continue;
}
mp[dsu.find(i * m + j)] += a[i][j];
}
}
int ans = 0;
for (const auto& entry : mp) {
ans = max(ans, entry.second);
}
cout << ans << endl;
}
int main() {
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
这是一份很特殊和有意思的解法。
hetanhnandre解题思路:
将每个的湖泊锁定一个点,例如:
3 3
1 2 0
3 4 0
0 0 5
左上角的湖泊锁定 ( 1 , 1 ) (1,1) (1,1),并且将旁边是同个湖泊的水深下标合并到该点,最后用map收集一下所有湖泊的值,然后取个最大值
并查集元素为坐标(经过转换的),也算是一种独特的解法了,不过要注意压缩路径和合并优化,减少并查集的高度。
F. Forever Winter(图)
题意:
给出一个图,图的形状为雪花。
图的给出方式为给出顶点数量 n n n,给出边数目 m m m,再给出 m m m个无向边的两个顶点 u , v u,v u,v
求雪花中心点的度和其中一个连接雪花中心的顶点的顶点数量(除中心点)
这两个答案为 x x x和 y y y
题解:
通过题目可知,一般情况是雪花中心点的度是唯一的,统计所有度的数量,如果发现有唯一值,就是雪花中心点的度,然后筛选除雪花中心点的度和度为1,剩下的就是连接雪花中心的顶点的顶点数量(除中心点)。
依据:题目给出 1 ≤ x , y 1\leq x,y 1≤x,y && x , y ≠ − 1 x,y \neq -1 x,y=−1,一般情况下算出的度有三种,其中一种有1个,另外一种度为1,剩下的就是y
坑点:当 x=y+1,也就是说找不到一个唯一值,三个数,除开度为1的值,剩下两种度的数一致,那么选其一当 x x x即可,按题意算 y y y是 x / ( 度为 1 的顶点数 ) x/(度为1的顶点数) x/(度为1的顶点数)或者按照特例算 y = x − 1 y=x-1 y=x−1都可以
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
const int N =1010;
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
void sove(void){
int n,m;
cin>>n>>m;
map<int,int>ma;
map<int,int>alls;
while(m--){
int u,v;cin>>u>>v;
ma[u]++;
ma[v]++;
}
int ans=0,ans2=0;
for(int i=1;i<=n;i++){alls[ma[i]]++;}
for(int i=1;i<=n;i++)if(alls[ma[i]]==1&&ma[i]!=1)ans=ma[i];
int j=1;
while(ma[j]==ans||ma[j]==1)j++;
if(ans==0){
for(int i=1;i<=n;i++) {
if (ma[i] != 1) {
ans = ma[i];
}
if(ma[i]==1){
ans2++;
}
}
ma[j]=ans+1;
cout<<ans<<' '<<ans2/ans<<endl;
//or
//cout<<ans<<' '<<ans-1<<endl;
return ;
}
cout<<ans<<' '<<ma[j]-1<<endl;
}
int main(void){
int t;cin>>t;
while(t--){
sove();
}
return 0;
}