T1 分糖果(candy)
题意:
法1: 暴力枚举 90pt
枚举L ~ R 中每种情况的,找到最优解。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, L, R;
cin >> n >> L >> R;
int res = 0;
for(int i = L; i <= R; i++){
res = max(res, i % n);
}
cout << res << endl;
return 0;
}
法2:发现规律 100pt
我们先找到最靠近L的一个n的倍数 x,那么 x - 1 可能是最优解,然后我们去判断 x - 1 的范围,如果在 L ~ R 之间,那么直接输出这个数 % n 也就是 n - 1,如果不在边界内,那我们就判断是要取右边界还是左边界 + n - 1。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, L, R;
cin >> n >> L >> R;
int res = 0;
res = (L + n - 1) / n * n;
res -- ;
if(res < L){
if(R - L >= n - 1){
cout << n - 1 << endl;
}
else cout << R % n << endl;
}
else {
if(res <= R)cout << n - 1 << endl;
else cout << R % n << endl;
}
return 0;
}
T2 插入排序(sort)
题意:
法1:模拟排序过程 40pt
当是操作1的时候直接修改,因为会保留下来,当是操作2的时候进行一次选择排序,注意提前备份和排序后取消备份,因为他不会保留下来。然后暴力模拟。
#include<bits/stdc++.h>
using namespace std;
const int N = 8e3 + 10;
int a[N], p[N], np[N];
int b[N], bp[N], bnp[N];
int main(){
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
p[i] = np[i] = i;
}
while(m --){
int t;
cin >> t;
if(t == 1){
int c, x;
cin >> c >>x;
a[c] = x;
}
else {
int x;
cin >> x;
// 备份
memcpy(b, a, sizeof a);
memcpy(bp, p, sizeof p);
memcpy(bnp, np, sizeof np);
// 模拟排序
for(int i = 2; i <= n; i ++){
for(int j = i ; j >= 2; j --){
if(a[j - 1] > a[j]){
swap(a[j], a[j - 1]);
np[p[j]] = j - 1;
np[p[j - 1]] = j;
swap(p[j], p[j - 1]);
}
}
}
cout << np[x] << endl;
memcpy(a, b, sizeof b);
memcpy(p, bp, sizeof bp);
memcpy(np, bnp, sizeof bnp);
}
}
return 0;
}
法2:排序过程中维护p和np数组 100pt
- 当我们修改一个点的时候,需要在这个点的排序后的位置往后往前进行迭代。其中p数组表示,排序后的 i 位置 在原数组的位置p[i]。np数组表示排序后的原数组i的位置在新数组的np[i]。 注意交换顺序。 注意用scanf 用cin会超时。
#include<bits/stdc++.h>
using namespace std;
const int N = 8e3 + 10;
int a[N], p[N], np[N];
int n, m;
// p 排序后 i位置的在原数组的
// np 排序后 原数组的 在新数组
void fd(int x){
for(int i = x; i > 1; i --){
// 如果 有相等的 按照原数组位置来排序
if(a[i - 1] == a[i] && p[i] > p [i - 1]) continue;
if(a[i - 1] >= a[i]){
swap(a[i], a[i - 1]);
np[p[i]] = i - 1;
np[p[i - 1]] = i;
swap(p[i], p[i - 1]);
}
}
}
void bk(int x){
for(int i = x; i < n; i ++){
// 如果 有相等的 按照原数组位置来排序
if(a[i + 1] == a[i] && p[i + 1] > p [i]) continue;
if(a[i + 1] <= a[i]){
swap(a[i], a[i + 1]);
np[p[i]] = i + 1;
np[p[i + 1]] = i;
swap(p[i], p[i + 1]);
}
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
p[i] = np[i] = i;
}
//提前进行排序操作。
for(int i = 2; i <= n; i ++){
fd(i);
}
while(m --){
int t;
scanf("%d", &t);
if(t == 1){
int c, x;
cin >> c >>x;
c = np[c];
a[c] = x;
bk(c);
fd(c);
}
else {
int x;
cin >> x;
cout << np[x] << endl;
}
}
return 0;
}
T3 网络连接(network)
题意:
法1 : 模拟 100pt
我会把我出过错的地方进行标注,注意这些细节!
#include<bits/stdc++.h>
#define int long long // 不开longlong 见祖宗
using namespace std;
map <string, int> mp;
signed main(){
int n;
cin >> n;
int tt = 1;
for(int i = 1; i <= n; i++){
map<char, int> cnt;
string a, b;
vector<int> v;
cin >> a >> b;
int f = 1;
string res = "";
for(int j = 0; j < b.size(); j ++){
if(b[j] == '.') res += b[j], cnt['.'] ++;
else if(b[j] == ':'){
res += b[j];
if(cnt['.'] != 3) f = 0;
// 当出现:时,前面三个.都要出现,也就是。不能出现在:后面
cnt[':'] ++;
}
else if(b[j] >= '0' && b[j] <= '9'){
int num = 0;
int j1 = j;
string temp = "";
while(b[j1] <= '9' && b[j1] >= '0' && j1 < b.size()) {
num = num * 10 ;
num += b[j1] - '0';
temp += b[j1];
j1 ++;
}
j = j1 - 1;
if(temp.size() > 1 && temp[0] == '0')f = 0;//前导0
res += temp;
v.push_back(num);
}
else f = 0;
}
for(int i = 0; i < v.size(); i++){
int num = v[i];
if(i == v.size() - 1){
if(num < 0 || num > 65535) f = 0;
}
else {
if(num < 0 || num > 255) f = 0;
}
}
// 。。
if( f == 0 || v.size() != 5|| cnt['.'] != 3 || cnt[':'] != 1){
cout << "ERR" << endl;
continue;
}
if(a[0] == 'S'){
if(mp.find(res) == mp.end()){
cout << "OK" << endl;
mp[res] = i;
}
else {
cout << "FAIL" << endl;
}
}
else {
if(mp.find(res) == mp.end()){
cout << "FAIL" << endl;
}
else {
cout << mp[res] << endl;
}
}
}
return 0;
}
T4 小熊的果篮
题意:
法1: 暴力模拟 70pt
在写这个模拟之前,你要知道规律是 01 交替出现,然后先找到第一个没有拿出的,记录他的种类,然后通过1 - pt 来进行交替互换,然后遍历就行。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 100;
int a[N], vis[N];
int main(){
int n, sum = 0;
cin >> n;
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
while(sum < n){
// 先找到第一个没有被拿走的
int pt = 0;
for(int i = 1; i <= n; i++){
if(!vis[i]) {
pt = a[i];
break;
}
}
for(int i = 1; i <= n; i++){
if(!vis[i]) {
if(pt == a[i]){
printf("%d ", i);
sum ++;
vis[i] = 1;
pt = 1 - pt;
}
}
}
cout << endl;
}
return 0;
}
法2: SET维护01的位置 100pt
如果0和1都有的话,那么他们肯定是交替出现的,因为如果他们不是交替的话,说明某一种水果已经全部取出。然后使用set中的lowerbound来找到离now最近的一个下标,交替输出同时保证下标递增即可,注意不能用cin cout!
#include<bits/stdc++.h>
using namespace std;
set<int>s[2];
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i++){
int x;
scanf("%d", &x);
s[x].insert(i);
}
while(s[0].size() || s[1].size()){
int pt = 0, now = 0;
set<int>::iterator s0, s1;
s0 = s[0].lower_bound(now);
s1 = s[1].lower_bound(now);
if(s[0].size() == 0)pt = 1;
else if(s[1]. size() == 0) pt =0;
else if(*s0 > *s1) pt = 1;
else pt = 0;
while(1){
auto t2 = s[pt].lower_bound(now);
// cout << *t2 << endl;
if(t2 == s[pt].end())break;
printf("%d ", *t2);
s[pt].erase(t2);
now = *t2;
pt = 1 - pt;
}
printf("\n");
}
return 0;
}