这次周赛选的是两次CF的题。
分别是168div2 170div2
A.Circle Line 水题
B.New Problem
这道题还是蛮有意思的,因为要注意到因为数据范围小而引起的变化。
但是这题n<= 30, 字符串长度<=20。
所以,最多有30*19个长度为2的子串。
但是长度为2的子串一共有26*26。
26*26 > 30*19。
所以这道题我们就只需要枚举长度1的子串和长度2的子串即可。
char a[100][100]; int vis[100]; int main() { int n ; while(cin >> n ) { memset(vis,0,sizeof(vis)); for (int i = 0 ;i < n ;i ++){ cin >>a[i]; for (int j = 0 ; j < strlen(a[i]); j ++) vis[a[i][j] - 'a'] ++; } for (int i = 0 ;i < 26; i ++)//枚举长度为1的子串 { if(!vis[i]) { char aa = i + 'a'; cout <<aa<<endl; return 0; } } // for (int i = 0 ;i < n ;i ++) // cout <<a[i]<<" "; for (int i = 0 ;i < 26 ;i ++)//枚举长度为2的子串 { for (int j = 0 ;j < 26 ;j ++) { char b[20]; char bb = i + 'a'; char cc = j +'a'; //b.clear(); //cout <<bb <<" "<<cc<<endl; //b = bb + cc; b[0]=bb; b[1]=cc; b[2] = 0; //cout <<b <<endl; bool flag = 0; for (int k = 0 ;k < n; k ++) { if(strstr(a[k],b) != 0) { //cout <<b<<" "<<a[k]<<endl; flag = 1; break; } } if(!flag) { cout<<b<<endl; return 0; } } } } }C。 Learning Languages
裸并查集。
写的略凌乱。
int man[1000]; int lan[1000]; int findl(int a) { return lan[a] == a?a:lan[a]=findl(lan[a]); } void unionl(int a,int b ) { a = findl(a); b = findl(b); if(a == b)return ; if(a > b)lan[a] = b; else lan[b] = a; } int vis[1000]; int main() { int n , m ; while(cin >> n >> m) { memset(vis,0,sizeof(vis)); for (int i = 0 ; i <= n ; i ++)man[i] = i; for (int i = 0 ; i <= m ; i ++)lan[i] = i; for (int i = 0 ; i < n ; i ++) { int k ; scanf("%d",&k); int pre = 0 ,d; if(k) { cin >> pre; } for (int j = 1 ; j < k ; j ++) { cin >> d; if(pre != d) unionl(pre,d);//将可以想通的语言合并 pre = d; } man[i] = pre; } for (int i = 0 ; i < n ; i ++)man[i] = findl(man[i]);//找到这个人属于哪个集合的语言 int ans = 0; for (int i = 0 ; i < n; i ++) { vis[man[i]] ++;//记录各种语言集合的人数 } if(vis[0])//如果有人什么语言都不会 , 那么这些人都要1的费用学习 ans += vis[0]; for (int i = 1 ; i <= m ; i ++) { if(vis[i])ans ++;//记录一共有多少种语言集合 每种花费1将其合并 } if(vis[0] == n) cout <<n<<endl; else cout <<ans - 1<<endl; } }
D。
E。
F。水题G。水题,爆搜即可。
但是我爆搜写的略挫,写了150行。。。凌乱的不行。写这题的时候思路太乱。。
#include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #include <vector> #include <stack> #include <map> #include <iomanip> #define PI acos(-1.0) #define Max 2005 #define inf 1<<28 #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define FOR(i,s,t) for(int i=(s);i<=(t);++i) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) using namespace std; int n , m ; char Map[100][100]; struct kdq { int x,y; } pp[10000]; int check(kdq x,kdq y) { if(x.x == y.x) { int m1 = min(x.y,y.y); int m2 = max(x.y,y.y); for (int i = m1 + 1 ; i < m2 ; i ++) if(Map[x.x][i] == 'W')return 0; } else if(x.y == y.y) { int m1 = min(x.x,y.x); int m2 = max(x.x,y.x); for (int i = m1 + 1 ; i < m2 ; i ++) if(Map[i][x.y] == 'W')return 0; } else { bool ans1 = 0 ,ans2 = 0; if(x.x < y.x) { if(x.y < y.y) { for (int i = x.y ; i <= y.y; i ++) { if(Map[x.x][i] =='W')ans1 = 1; if(Map[y.x][i] == 'W')ans2 = 1; } for (int i = x.x ; i <= y.x ; i ++) { if(Map[i][x.y] == 'W')ans2 =1 ; if(Map[i][y.y] == 'W')ans1 = 1; } if(ans1 &&ans2 )return 0; } else { for (int i = y.y ; i <= x.y ; i ++) { if(Map[x.x][i] =='W')ans1 = 1; if(Map[y.x][i] == 'W')ans2 = 1; } for (int i = x.x ; i <= y.x ; i ++) { if(Map[i][x.y] == 'W')ans2 =1 ; if(Map[i][y.y] == 'W')ans1 = 1; } if(ans1 &&ans2 )return 0; } } else { if(x.y < y.y) { for (int i = x.y ; i <= y.y; i ++) { if(Map[x.x][i] =='W')ans1 = 1; if(Map[y.x][i] == 'W')ans2 = 1; } for (int i = y.x ; i <= x.x ; i ++) { if(Map[i][x.y] == 'W')ans2 = 1; if(Map[i][y.y] == 'W')ans1 = 1; } if(ans1 && ans2 )return 0; } else { for (int i = y.x ; i <= x.x ; i ++) { if(Map[i][x.y] == 'W')ans1 =1 ; if(Map[i][y.y] == 'W')ans2 = 1; } for (int i = y.y ; i <= x.y; i ++) { if(Map[x.x][i] == 'W')ans2 = 1; if(Map[y.x][i] == 'W')ans1 =1 ; } if(ans1 && ans2 )return 0; } } } return 1; } int main() { cin >> n >> m; int num = 0; for (int i = 0 ; i < n ; i ++) { scanf("%s",Map[i]); for (int j = 0 ; j < m ; j ++) { if(Map[i][j] == 'B') { pp[num ].x = i,pp[num ].y = j; num ++; } } } bool flag = 0 ; for (int i = 0 ; i < num ; i ++) { for (int j = i + 1 ; j < num ; j ++) { if(check(pp[i],pp[j]) == 0) flag = 1; } if(flag)break; } if(!flag) cout <<"YES"<<endl; else cout <<"NO"<<endl; }
H。贪心。
I。Zero Tree
题意:给你一棵树,有n个节点, n-1 条边,每个节点有一个值。
有一个操作,选择一颗包含节点1的子树,这棵子树可以加1或者减1
问最少经过多少次操作,使所有节点的值为0。
思路:我们可以将这棵树看成以节点1 为祖先的一棵树。每次都搜到根节点,每次从节点1到这个根节点之间的子树,根据根节点的值进行加减,处理完之后,这个根节点就不需要使用了,其他子树也不会包括这个根节点。
那么显然,可以用递归实现,搜到根节点,然后层层更新。最后更新到节点1,输出节点1加减的值即为总值。
vector<int>q[Max]; __int64 value[Max]; __int64 add[Max]; __int64 des[Max]; int max(int a,int b) { return a>b?a:b; } void dfs(int now, int pre) { for (int i = 0 ;i < q[now].size(); i ++) { int next = q[now][i]; if(next != pre) { dfs(next,now); add[now] = max(add[now], add[next]); des[now] = max(des[now], des[next]); } } value[now] = value[now] + add[now] - des[now]; if(value[now] < 0) add[now] += -(value[now]); else des[now] += value[now]; } int main() { int n ; cin >> n ; int a,b; for (int i = 0 ;i < n - 1 ; i++){ scanf("%d%d",&a,&b); q[b].push_back(a); q[a].push_back(b); } for (int i = 1; i <= n ; i++)scanf("%I64d",&value[i]); dfs(1,-1); cout << add[1] + des[1] <<endl; }这算是上周的任务了。。
明天还得继续把今天周赛的题给A掉=。=