CF1220
CF1220
A
one和zero特的字母分别是'n'和'z'
输出他们的数量即可
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
#define min std::min
#define max std::max
const int N = 3e5 + 3;
char s[N];
int sum[N];
int n;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int main(){
n = read();
scanf("%s",s + 1);
for(int i = 1;i <= n;++i) sum[s[i]]++;
int cnt = 0;
while(sum['n']){
cnt++;
printf("1 ");
sum['n']--;
}
while(sum['z']){
printf("0 ");
sum['z']--;
}
return 0;
}
B
给你一个\(n * n\)的矩阵,第\((i,j)\)个位置表示\(a_i \times a_j\)(对角线为\(0\))
求数组\(a\)
对于任意三个\((i,j,k)\)
我们有\(a_i^2 = \frac{a_i \times a_j \times a_k \times a_j}{a_j \times a_k}\)
所以按照这种方式可以求出每个\(a_i^2\),最后开根号即可
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
#define min std::min
#define max std::max
const int N = 1005;
LL a[N][N];
LL ans[N];
int n,m;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int main(){
n = read();
for(int i = 1;i <= n;++i) for(int j = 1;j <= n;++j) a[i][j] = read();
for(int i = 1;i <= n;++i){
int x = 0,y = 0;
if(i <= n - 2) x = i + 1,y = i + 2;
else if(i == n - 1) x = 1,y = n;
else x = 1,y = 2;
ans[i] = a[i][x] * a[i][y] / a[x][y];
}
for(int i = 1;i <= n;++i) printf("%.0lf ",sqrt((double)ans[i]));
return 0;
}
C
给定一个字符串\(s\)
游戏规则
当前在\([l,r]\)每次只能扩展到\([l',r']\)使得\(l' \le l,r \ge r\)且\(s[l',r']\)的字典序比\(s[l,r]\)要小,不能走的时候对方获胜
对于每个\(i\),求出当初始状态为\([i,i]\)时,先手是否必胜
很明显,只要存在\(s[l', r']\)满足条件,那么先手一定可以移动到最优解,那么只需要判断是否存在比现在这个状态字典序更小的状态存在即可
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
#define min std::min
#define max std::max
const int N = 1e6 + 3;
char s[N];
int sum[27][N];
int n;
int ans = 0x3f3f3f3f;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int main(){
scanf("%s",s + 1);
n = strlen(s + 1);
for(int i = n;i >= 1;--i){
for(int j = 0;j < 26;++j) sum[j][i] = sum[j][i + 1];
sum[s[i] - 'a'][i]++;
}
for(int i = 1;i <= n;++i){
bool flag = 0;
for(int j = s[i] - 'a' - 1;j >= 0;--j) if(sum[j][1] - sum[j][i] > 0) flag = 1;
if(!flag)
printf("Mike\n");
else printf("Ann\n");
}
return 0;
}
D
题目大意:给定一个正整数集合\(B\)。
让所有整数都为一张无向图中的顶点。\(i, j\)之间有边,当且仅当\(\left| i - j\right| \in B\)
现在要从\(B\)中删去最少的元素,使得这张无向图变成二分图
首先二分图的定义:不存在奇环
首先对于\(B\)中的元素\(x,y\)
若
这个式子如果是奇数,那么存在奇环
我们分类讨论一下
若\(x,y\)是奇数
那么上面的式子一定是偶数
若\(x,y\)是一奇一偶,那么上面的式子是偶数
如果\(x,y\)是偶数
那么我们就设\(x = 2x' ,y = 2y'\)
发现就变成了一个子问题,直到出现一奇一偶或者全是奇数的情况就能判断他们能否共存
发现第三种情况的本质就是这两个数的二进制末尾0个数是否相同
(因为不断除二,判断奇偶性)
所以我们由二推多,末尾0个数相同的可以共存,所以最终答案就是\(n\)减去最多的一类
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
#define min std::min
#define max std::max
const int N = 5e5 + 3;
inline LL read(){
LL v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int n;
LL a[N];
LL num[N];
int cnt[N];
int main(){
n = read();
for(int i = 1;i <= n;++i) a[i] = read();
for(int i = 1;i <= n;++i){
LL x = a[i];
while((x & 1) == 0){
num[i]++;
x >>= 1;
}
cnt[num[i]]++;
}
int sum = 0,id = 0x3f3f3f3f;
for(int i = 0;i <= n;++i)
if(sum < cnt[num[i]]) sum = cnt[num[i]],id = num[i];
printf("%d\n",n - sum);
for(int i = 1;i <= n;++i){
if(num[i] != id) printf("%lld ",a[i]);
}
return 0;
}
E
题目大意
给定一个无向图,点有点权(非负),不能连续通过同一条边,一条从\(S\)出发的路径使得点权和最大(重复经过算一次)
(这里的环定义貌似有点奇特,图中的非黄色点都属于环)
首先,如果存在环,那么这和环上的点我们都是可以经过的
所以我们只需要考虑不在换上的点的贡献,之后发现如果我们走进了这种点
就再也不能回头
比如说图中黄色的点,我们一旦从环上走了进去,就只能向下走
我们一定先去把换上的点先跑一边,之后再剩下的点没被经过的点中选一条向下点权和最大的点即可
考虑如何去实现这个过程,首先找环
可以使用类拓扑排序找到环,然后可以证明,环上的点都是可以算进贡献的
是不是我们再寻找一条最大路径就好了
但是注意我们只是讨论了起点再环上的情况
若起点不在环上,最优解可能是这个样子
蓝色部分
也就是说,\(S\)到环上的路径也成为了恒有贡献的部分
(即使最优解在\(S\)的下边我们也可以上去再下来)
所以把这一块也标记一下就好了
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<cmath>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
#define min std::min
#define max std::max
const int N = 5e5 + 3;
LL w[N];
struct edge{
int to;
int nxt;
}e[N << 1];
LL f[N];
int n,m;
LL ans,res;
int s;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int tot,cnt;
int head[N],d[N];
bool used[N],flag[N];LL dp[N];
int fa[N];
inline void add(int x,int y){
e[++tot].to = y;
e[tot].nxt = head[x];
head[x] = tot;
}
inline void pre(){
flag[s] = 1;
std::queue <int> q;
for(int i = 1;i <= n;++i) if(d[i] == 1) q.push(i),f[i] = w[i];
while(!q.empty()){
int k = q.front();used[k] = 1;q.pop();
for(int i = head[k];i;i = e[i].nxt){
int y = e[i].to;
if(used[y]) continue;
f[y] = max(f[y],f[k] + w[y]);
flag[y] |= flag[k];
d[y]--;
if(d[y] == 1) q.push(y);
}
}
}
inline void dfs(int x,int f){
for(int i = head[x];i;i = e[i].nxt){
int y = e[i].to;
if(y == f) continue;
dfs(y,x);
dp[x] = max(dp[x],dp[y]);
}
dp[x] += w[x];
}
int main(){
n = read(),m = read();
for(int i = 1;i <= n;++i) w[i] = read();
for(int i = 1;i <= m;++i){
int x = read(),y = read();
add(x,y);
add(y,x);
d[x]++,d[y]++;
}
s = read();
if(m == n - 1){
dfs(s,0);
printf("%lld\n",dp[s]);
return 0;
}
pre();
for(int i = 1;i <= n;++i) if(flag[i]) ans += w[i],f[i] = 0;
for(int i = 1;i <= n;++i){
if(flag[i]) continue;
if(used[i]) res = max(res,f[i]);
else ans += w[i];
}
printf("%lld\n",ans + res);
return 0;
}