A
题意:
每次操作可以让第一个数字加1,第一个数字之后的数字减1,问你最少变换多少可以使得第一个数字大于后面所有数字。
解析:
先保存下所有的数字,以及该数字出现的个数。
直接用map,每次取得map中最大的数字让这个数字的个数减去1,再把a[0]加一,在把这个最大的数字减去1,存入map中,直至a[0]大于所有的数字,输出最少的操作次数。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1005;
int a[N], n;
map<int, int> mp;
map<int, int>::iterator it;
int main() {
while(~scanf("%d", &n)) {
mp.clear();
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
if(i > 0) mp[a[i]]++;
}
it = mp.end(); it--;
int ans = 0, maxa = it->first;
while(a[0] <= maxa) {
a[0]++; ans++;
mp[maxa]--; mp[maxa-1]++;
if(mp[maxa] == 0) it--;
maxa = it->first;
}
printf("%d\n", ans);
}
return 0;
}
B
题意:
n个人,m个询问,然后接下来m行告诉你a与b是相互认识的,但是这个认识不能够相互传递,也就是说a认识b,b认识c,但是a并不认识c。
然后问你是否能够在这n个人中选取3个人,使得它们认识其他人的总数最少,并且这三个人要相互认识(也就是a-b,b-c,c-a),如果不存在则输出-1
解析:
枚举两条边判断这两条边能否构成三角形。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 4005;
struct Edge {
int u[2];
} edge[N];
int n, m;
int deg[N];
bool G[N][N];
int check(int x, int y) {
int ret = INF;
int a, b, c, d;
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 2; j++) {
a = edge[x].u[i];
b = edge[y].u[j];
c = edge[x].u[i^1];
d = edge[y].u[j^1];
if(a == b && G[c][d]) {
ret = deg[a] + deg[c] + deg[d] - 6;
return ret;
}
}
}
return ret;
}
int cal() {
int ret = INF;
for(int i = 0; i < m; i++) {
for(int j = i+1; j < m; j++) {
ret = min(ret, check(i, j));
}
}
return ret == INF ? -1 : ret;
}
int main() {
int u, v;
while(~scanf("%d%d", &n, &m)) {
memset(deg, 0, sizeof(deg));
memset(G, 0, sizeof(G));
for(int i = 0; i < m; i++) {
scanf("%d%d", &u, &v);
if(v == u || G[u][v]) continue;
G[u][v] = G[v][u] = true;
deg[u]++, deg[v]++;
edge[i] = (Edge){u, v};
}
printf("%d\n", cal());
}
return 0;
}
C
题意:
现在有n个人,每个人都持有a[i]这个价值的牌,并且每个人可以每次无限次数的使自己的牌扩大2倍,扩大3倍,然后问你是否可能使得最终所有人的牌的价值数变成一样的。
思路:
可以逆向思维,既然这些数字乘以无限多的2和3可以得到一样的数字,那么这些数字,不停的除以2与3,剩下的数字也可以通过不断的乘以2或者3得到。
所以我们可以使所有的数都不停的除以2与3,直到不能除为止,然后判断除完以后所有的数是否相同,如果相同,则说明是可以的,否则,则是不可以的。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = (int)1e5 + 10;
int a[N], n;
bool judge() {
for(int i = 1; i < n; i++)
if(a[i] != a[i-1])
return false;
return true;
}
int main() {
while(~scanf("%d", &n)) {
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
for(int i = 0; i < n; i++) {
while(a[i]%2==0) a[i]/=2;
while(a[i]%3==0) a[i]/=3;
}
puts(judge() ? "Yes" : "No");
}
return 0;
}
D
题意:
有n个方格,然后每个方格都有一个高度,然后每次都可以把那些非完整块(就是它的四个方向没有被完全包围)给连在一起消去。问你最后把所有的方块消去需要几次。
解析:
就是求最高的 1, 2, 3, 4 …, 4, 3, 2, 1这样的等腰三角形的高度。
首先初始化为 L[0]=0,R[n+1]=0 ,我们设两个数组L代表的是从左边开始消去每次的最大高度,R则是右边的。
L[i]=min(h[i],L[i−1]+1)
R[i]=min(h[i],R[i+1]+1)
ans=max(ans,min(L[i],R[i]))
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int h[N], L[N], R[N];
int n;
int main() {
while(~scanf("%d", &n)) {
for(int i = 1; i <= n; i++) {
scanf("%d", &h[i]);
}
L[0] = R[n+1] = 0;
for(int i = 1; i <= n; i++) {
L[i] = min(L[i-1] + 1, h[i]);
}
for(int i = n; i >= 1; i--) {
R[i] = min(R[i+1] + 1, h[i]);
}
int ans = 0;
for(int i = 1; i <= n; i++) {
ans = max(ans, min(L[i], R[i]));
}
printf("%d\n", ans);
}
return 0;
}