A 三角形
分析:我们可以先简化一下问题,如果没有限制哪挑边不能够用,那么我们怎么求一个三角形的最大周长,很简单, sort一下, 然后从最高边权开始尺取每次枚举三条边 第一个可以构成三角形的就是最大周长。现在这里要问某些边不能够使用, 我们sort的时候记录每个边的id,就好了。这样如果有一条边不能够用,我们顺延就好了。
看代码吧
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 11;
struct Ques{
int id, a;
Ques(){}
Ques(int _id, int _a){
id = _id; a = _a;
}
}ques[N];
int n, q;
bool cmp(Ques a, Ques b){
return a.a > b.a;
}
ll solve(int x){
for(int i = 1; i + 2 <= n; i++){
int a = i, b = i + 1, c = i + 2;
if(ques[a].id == x){
a++ ; b++; c++;
}else if(ques[b].id == x){
b++; c++;
}else if(ques[c].id == x){
c++;
}
if(c > n) continue;;
if(ques[a].a < ques[b].a * 1ll + ques[c].a) {
return ques[a].a * 1ll + ques[b].a + ques[c].a; // 注意ll
}
}
return -1;
}
int main(){
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i++){
int val; scanf("%d", &val);
ques[i] = Ques(i, val);
}
sort(ques + 1, ques + 1 + n, cmp);
while(q--){
int x; scanf("%d", &x);
printf("%lld\n", solve(x));
}
return 0;
}
解法二,看到别人暴力也可以过,学习一波; 我只需要求出大多数询问的最大值,如果涉及到小部分,我们再重新暴力一次 代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = (int) 1e5 + 11;
const int M = (int) 1e5 + 11;
const int mod = (int) 1e9 + 7;
const int inf = 0x3f3f3f3f;
int a[N], Rank[N];
bool cmp(int x, int y){
return a[x] > a[y];
}
bool vis[N]; ll ans[N];
int main(){
int n, q; scanf("%d%d", &n, &q);
for(int i = 0; i < n; i++) scanf("%d", &a[i]), Rank[i] = i;
sort(Rank, Rank + n, cmp);
ll MX = -1;
for(int i = 0; i < min(n, 30); i++){
vis[Rank[i]] = 1;
for(int j = i + 1; j < min(n, 30); j++){
for(int k = j + 1; k < min(n, 30); k++){
int I = a[Rank[i]], J = a[Rank[j]], K = a[Rank[k]];
if(I + J > K && I + K > J && K + J > I){
MX = max(MX, I * 1ll + J + K);
}
}
}
//printf("%lld\n", MX);
}
for(int o = 0; o < n; o++){
if(!vis[o]) ans[o] = MX;
else {
ll MM = -1;
for(int i = 0; i < min(n, 30); i++){
if(o == Rank[i]) continue;
for(int j = i + 1; j < min(n, 30); j++){
if(o == Rank[j]) continue;
for(int k = j + 1; k < min(n, 30); k++){
if(o == Rank[k]) continue;
int I = a[Rank[i]], J = a[Rank[j]], K = a[Rank[k]];
if(I + J > K && I + K > J && K + J > I){
MM = max(MM, I * 1ll + J + K);
}
}
}
}
ans[o] = MM;
}
}
while(q--){
int val; scanf("%d", &val);
printf("%lld\n", ans[val - 1]);
}
return 0;
}
B 博弈论
分析: 很明显,最终的出现断层的位数一定不大。这样就足够了
代码
#include <bits/stdc++.h>
using namespace std;
const int N = (int) 1e3 + 11;
typedef long long ll;
int s[N + 1];
map<ll, bool>mp;
map<ll, bool>:: iterator it;
int main(){
int n; scanf("%d" ,&n);
for(int i = 0; i < n; i++) scanf("%d" ,&s[i]);
for(int i = 1; i <= n && i <= 16 ; i++){
for(int j = 0; j + i - 1 < n; j++){
ll tmp = 0;
for(int k = j; k <= j + i - 1; k++){
tmp = tmp * 10 + s[k];
}
//printf("%lld \n", tmp);
mp[tmp] = 1;
}
}
ll id = 0;
for(it = mp.begin(); it != mp.end(); it++){
if(it->first != id) {
break;
}else id++;
}
printf("%lld\n", id);
return 0;
}
C 病菌感染
分析: 暴力
代码
#include <bits/stdc++.h>
using namespace std;
const int N = (int) 1e3 + 11;
bool mp[N][N];
int to [4][2] ={1, 0, -1, 0, 0, 1, 0, -1};
int main(){
int n, m; scanf("%d%d", &n, &m);
while(m--){
int a, b; scanf("%d%d", &a, &b);
mp[a][b] = 1;
}
int flag = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(mp[i][j]) continue;
int cnt = 0;
for(int k = 0; k < 4; k ++){
int x = i + to[k][0]; int y = j + to[k][1];
if(x < 1 || y < 1 || x > n || y > n) continue;
if(mp[x][y]) cnt ++;
if(cnt >= 2){
flag++;
break;
}
}
}
}
if(flag == n * n - m) puts("YES");
else puts("NO");
return 0;
}
D 郊区春游
分析: 因为只和这R个景区有关,所以我们先预处理出来任意两个点之间的最短距离,然后就是典型的TSP问题, 记忆化搜索一下。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = (int) 1e3 + 11;
const int M = (int) 1e5 + 11;
const int mod = (int) 1e9 + 7;
const int inf = 0x3f3f3f3f;
int dis[N][N];
void init(int n){
for(int i = 0; i <= n; i++){
for(int j = 0; j <= n; j++){
if(i == j) dis[i][j] = 0;
else dis[i][j] = dis[j][i] = inf;
}
}
}
void floyd(int n){
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
}
int pos[N], dp[1 << 16][16]; int r;
int TSP(int s, int v){ // 已经走过的状态为s, 并且当前在v位置
if(dp[s][v] != -1) return dp[s][v];
if(s == (1 << r) - 1) return dp[s][v] = 0;
int res = inf;
for(int i = 0; i < r; i++){
if(!((s >> i) & 1)){
res = min(res, TSP(s | (1 << i), i) + dis[pos[v]][pos[i]]);
}
}
return dp[s][v] = res;
}
int main(){
int n, m; scanf("%d%d%d", &n,&m, &r);
init(n);
for(int i = 0; i < r; i++) scanf("%d", &pos[i]);
while(m--){
int a, b, c; scanf("%d%d%d", &a, &b, &c);
dis[a][b] = dis[b][a] = min(dis[a][b], c );
}
floyd(n);
memset(dp, -1, sizeof(dp));
int ans = inf;
for(int i = 0; i < r; i++) // 因为不确定起点,所以我们遍历所有
ans = min(ans, TSP(1 << i, i));
printf("%d\n", ans);
return 0;
}
E 浮点数输出
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
string s; cin>>s;
cout<<s;
return 0;
}
F 等价串
分析: 哇,自己想的真难想啊,其实只要想对方向,这题真的挺简单。如果A串可以到达B串,那么说明 A串在原串的情况下 全部变为0,和B串也全部变为0,本质上应该是一样的,因为三个0可以删除掉,所以只要模三后相同就足够了
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = (int) 1e3 + 11;
const int M = (int) 1e5 + 11;
const int mod = (int) 1e9 + 7;
const int inf = 0x3f3f3f3f;
char A[N], B[N];
int change(char *s){
int cnt = strlen(s);
for(int i = 0; s[i]; i++){
if(s[i] == '1') cnt ++;
}
return cnt;
}
int main(){
int T; scanf("%d", &T);
while(T--){
int n, m; scanf("%d%d" ,&n, &m);
scanf("%s%s", A, B);
bool flag = change(A) % 3 == change(B) % 3;
puts(flag ? "YES" : "NO");
}
return 0;
}
H 相邻的糖果
分析:尺取的去维护 每m堆的值。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = (int) 1e6 + 11;
const int M = (int) 1e5 + 11;
const int mod = (int) 1e9 + 7;
int a[N];
int main(){
int n, m, x; scanf("%d%d%d", &n, &m, &x);
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
}
ll ans = 0; ll sum = 0;
for(int i = 0; i < m; i++) sum += a[i];
int id = m - 1;
while(sum > x){ // 先预处理好前m项,贪心的最后一位开始减少值
if(sum - a[id] >= x){
sum -= a[id];
ans += a[id];
a[id] = 0;
}
else {
a[id] -= sum - x;
ans += sum - x;
sum = x;
}
id--;
}
for(int i = m; i < n; i++){
sum += a[i];
sum -= a[i - m];
if(sum > x){ // 如果一旦出现大于x的情况,那么一定是由于加上a[i]导致的
ans += sum - x;
a[i] -= sum - x;
sum = x;
}
}
printf("%lld\n", ans);
return 0;
}
I 合唱队形
好像写的复杂了
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = (int) 1e5 + 11;
int pos[N];
int n;
void get(int id, int &l, int &r){// 从id位开始,第一个连续的女生左右区间
l = r = id;
while(id < n && pos[id]) id ++;
if(id < n) {
l = id;
while(id < n && !pos[id]) id ++;
if(id < n) {
r = id - 1;
}else r = n - 1;
}else l = -1;
}
int main(){
scanf("%d" ,&n);
string s; cin >>s;
int ge = 0;// 男生个数
for(int i = 0; i < n; i++){
pos[i] = s[i] - '0';
ge += pos[i];
}
int mx = 0; int cnt = 0;
for(int i = 0; ; ){
int l, r;
get(i, l, r);
if(l == -1) break;
mx = max(mx, r - l + 1);
if(r - l + 1 != n - ge) mx = max(mx, r - l + 2);
i = r + 1;
}
int a, b, c, d;
get(0, a, b);
if(a != -1)
for(int i = b + 1; ; ){
get(i, c, d);
if(c == -1) break;
if(b + 2 == c){
int dis = (b - a + 1) + (d - c + 1);
mx = max(mx, dis);
if(dis < n - ge) mx = max(mx, dis + 1);
}
a = c; b = d ;
i = d + 1;
}
printf("%d\n", mx);
return 0;
}
J 强迫症
分析: 每次把目前最大的数加到一个重复的数上
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = (int) 1e5 + 11;
map<int, int>mp;
map<int, int>::iterator it;
int main(){
int n; scanf("%d" ,&n);
for(int i = 0; i < n; i++){
int val; scanf("%d" ,&val);
mp[val] ++;
}
int ans = 0;
for(it = mp.begin(); it != mp.end(); it++){
ans += it->second - 1;
}
printf("%d\n", ans);
return 0;
}