补完继续更……
A.
简单地模拟题,给出月份m和该月第一天的星期数d,问在图中的日历中需要写几列。写一个公式即可。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <functional>
//#include <iomanip.h>
#include <limits.h>
//#include <strstrea.h>
//#include <fstream.h>
#define ll long long
#define ull unsigned long long
//#define int64 long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e4 + 5;
int n, w, d;
int main() {
scanf("%d%d", &n, &w);
if (1 == n || n == 3 || n == 5 || n == 7 || n == 8 || n == 10 || n == 12) d = 31;
else if (n == 2) d = 28;
else d = 30;
int ans = 0;
ans++;
d -= (7 - w + 1);
if (d % 7 == 0) ans += (d / 7);
else ans += (d / 7 + 1);
printf("%d\n",ans);
return 0;
}
题目大意:有n张床,一共m个枕头,Frodo睡在第k张床上,每张床上至少有一个枕头,每张床与相邻的床的枕头数只差最大为1,求能分配给Frodo最多几个枕头。
解析:直接二分答案,每次计算当分配给Frodo now 个枕头时所有床上的最少的枕头数,与m比较即可
反思:这个题刚开始思路是对的,但是二分写的不对……改了改二分的姿势就过了……原来一直用的姿势竟然wa了我就很尴尬……
代码:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <functional>
//#include <iomanip.h>
#include <limits.h>
//#include <strstrea.h>
//#include <fstream.h>
#define ll long long
#define ull unsigned long long
//#define int64 long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e4 + 5;
ll n, m, k;
bool check(ll now) {
ll sum = 0;
if (now >= k) {
sum = sum + (2 * now - k) * (k - 1) / 2;
} else {
sum = sum + now * (now - 1) / 2 + k - now;
}
sum += now;
if (now - n + k >= 1) {
sum = sum + (2 * now - 1 - n + k) * (n - k) / 2;
} else {
sum = sum + now * (now - 1) / 2 + n - k - now + 1;
}
//cout << "now=" << now << " k=" << k << " sum=" << sum << endl;
return sum <= m;
}
int main() {
scanf("%I64d%I64d%I64d", &n, &m, &k);
ll l = 1, r = 1e9, mid, mmax;
while (l <= r) {
mid = (l + r) >> 1;
if (check(mid)) {
mmax = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
printf("%I64d\n", mmax);
return 0;
}
C.
题目大意:题目比较难翻译,最初的题意是n根烤串架在n个位置上烤,给出一个排列p,p[i]表示经过1s后将位置i上的烤串放到位置p[i]上继续烤,同时给出一个序列b[i],b[i]==1时表示烤串放到位置i上时要调转方向,求要使每一根烤串都能在这n种位置上每个方向都考一遍最少需要修改排列p和序列b上的几个数。
反思:比赛时通过画图发现对于一个排列p,每个位置上的数都属于一个循环,即在这个循环中最后会回到自己最初的位置,同一个循环中的k个位置是等效的,即它们彼此可以任意交换但不会跳出循环。当一个排列产生1个循环时无需调整,当产生两个循环时就需要调整p[i]和p[j]使得这两个循环变成一个循环,因此可得对于n个循环(n>1)需要调整n个数使得排列符合题意。然后我们再考虑序列b,对于序列b,假设p符合要求后b中有偶数个1,那么对于任意的位置i,循环完一个周期回到最初位置时的方向应该和最初的方向是相同的,也就是无论循环多少次在每个位置上的方向都是不变的,因此需要b中有奇数个1,使得回到最初位置后i的方向发生改变,那么第二个周期结束后就可以遍历每个位置上的所有方向。
代码:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <functional>
//#include <iomanip.h>
#include <limits.h>
//#include <strstrea.h>
//#include <fstream.h>
#define ll long long
#define ull unsigned long long
//#define int64 long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 5;
int n, b[maxn], p[maxn];
bool vis[maxn];
int f() {
memset(vis, false, sizeof(vis));
int cnt = 0;
for (int i = 1; i <= n; i++) {
if (!vis[i]) {
vis[i] = true;
cnt++;
int t = p[i];
while (t != i) {
vis[t] = true;
t = p[t];
}
}
}
return cnt;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
int cnt = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
if (b[i] == 1) cnt++;
}
int ans = f();
if (ans == 1) ans = 0;
if (cnt % 2 == 0) ans++;
printf("%d\n", ans);
return 0;
}
剩下的水平不够比赛时没来得及看……等补完再更好了
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------