2021新生赛破防试水
因为又菜又忙所以缓慢不定时更新
菜死了,找个签到题都很难,哭。
A.
签到,pass
M.
贪心。
求最悲观情况下低情商人数:从左往右遍历,遇到1把cnt变为0,cnt在k以下的计入ans2
最乐观情况:从左往右遍历,cnt > k的1把cnt变为0,cnt <= k的全部计入ans1
比较玄学的贪心,因为没有oj不知道对不对,只自己测了几个测试案例
s开到20010 SF了,开到200010 ac了(奇怪)
#include <bits/stdc++.h>
using namespace std;
char s[20010];
int n, k, ans1 = 0, ans2 = 0, cnt = 0, ok = 0;
int main () {
cin >> n >> k;
cin >> s;
for (int i = 0; i < n; i++) {
cnt ++;
if (s[i] == '1' ) {
if (cnt <= k && ok) ans2 ++;
ok = 1;
cnt = 0;
}
}
ok = 0, cnt = 0;
for (int i = 0; i < n; i++) {
cnt ++;
if (s[i] == '1') {
if (cnt <= k && ok) ans1 ++;
if (cnt > k || !ok) cnt = 0;
ok = 1;
}
}
cout << ans1 << ' ' << ans2 << endl;
return 0;
}
\std.out
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define SZ(v) ((int)v.size())
#define fs first
#define sc second
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
int n,k,sum;
char s[200010];
int main(){
cin>>n>>k;
scanf("%s",s+1);
assert(n<=200000&&k<=100&&strlen(s+1)==n);
int lst=-1000000,heq=0,ans=0;
rep(i,1,n){
if(s[i]=='1'){
sum++;
if(i-lst>k){
heq++;
lst=i;
}
}
}
lst=-1000000;
rep(i,1,n){
if(s[i]=='1'){
if(i-lst<=k) ans++;
lst=i;
}
}
printf("%d %d\n",sum-heq,ans);
return 0;
}
J.
直接模拟,摆烂了QAQ
暴力枚举行列式
#include <bits/stdc++.h>
using namespace std;
int a[1010][1010];
int s(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
return a[x1][y1] * a[x2][y2] - a[x3][y3] * a[x4][y4];
}
void solve (int n, int c) {
if (n == 1) cout << c << endl;
else if (n == 2) {
int ans1 = c * a[2][2] - a[1][2] * a[2][1]; int res = ans1;
int ans2 = a[1][1] * c - a[1][2] * a[2][1]; res = max(res, ans2);
int ans3 = a[1][1] * a[2][2] - c * a[2][1]; res = max(res, ans3);
int ans4 = a[1][1] * a[2][2] - a[1][2] * c; res = max(res, ans4);
cout << res << endl;
}
else {
int ans1 = c * s(2,2,3,3,2,3,3,2) - a[1][2] * s(2,1,3,3,2,3,3,1) + a[1][3] * s(2,1,3,2,2,2,3,1); int res = ans1;
int ans2 = a[1][1] * s(2,2,3,3,2,3,3,2) - c * s(2,1,3,3,2,3,3,1) + a[1][3] * s(2,1,3,2,2,2,3,1); res = max(res, ans2);
int ans3 = a[1][1] * s(2,2,3,3,2,3,3,2) - a[1][2] * s(2,1,3,3,2,3,3,1) + c * s(2,1,3,2,2,2,3,1); res = max(res, ans3);
int ans4 = -c * s(1,2,3,3,1,3,3,2) + a[2][2] * s(1,1,3,3,1,3,3,1) - a[2][3] * s(1,1,3,2,1,2,3,1); res = max(res, ans4);
int ans5 = -a[2][1] * s(1,2,3,3,1,3,3,2) + c * s(1,1,3,3,1,3,3,1) - a[2][3] * s(1,1,3,2,1,2,3,1); res = max(res, ans5);
int ans6 = -a[2][1] * s(1,2,3,3,1,3,3,2) + a[2][2] * s(1,1,3,3,1,3,3,1) - c * s(1,1,3,2,1,2,3,1); res = max(res, ans6);
int ans7 = c * s(1,2,2,3,1,3,2,2) - a[3][2] * s(1,1,2,3,2,1,1,3) + a[3][3] * s(1,1,2,2,1,2,2,1); res = max(res, ans7);
int ans8 = a[3][1] * s(1,2,2,3,1,3,2,2) - c * s(1,1,2,3,2,1,1,3) + a[3][3] * s(1,1,2,2,1,2,2,1); res = max(res, ans8);
int ans9 = a[3][1] * s(1,2,2,3,1,3,2,2) - a[3][2] * s(1,1,2,3,2,1,1,3) + c * s(1,1,2,2,1,2,2,1); res = max(res, ans9);
cout << res << endl;
}
}
int main () {
int t, n, c;
cin >> t;
while (t--) {
cin >> n >> c;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
solve (n, c);
}
return 0;
}
然后发现被标答薄纱
#include <bits/stdc++.h>
using namespace std;
int a[4][4];
int calc(int n) {
if (n == 1) return a[1][1];
if (n == 2) return a[1][1] * a[2][2] - a[1][2] * a[2][1];
return a[1][1] * a[2][2] * a[3][3] + a[1][2] * a[2][3] * a[3][1] + a[1][3] * a[2][1] * a[3][2] - a[1][3] * a[2][2] * a[3][1] - a[1][2] * a[2][1] * a[3][3] - a[1][1] * a[2][3] * a[3][2];
}
int main() {
int t, n, c;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) scanf("%d", &a[i][j]);
}
int mx = -1e9;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int tmp = a[i][j];
a[i][j] = c;
mx = max(mx, calc(n));
a[i][j] = tmp;
}
}
printf("%d\n", mx);
}
return 0;
}
E.
第二简单的签到,打印图形问题
#include <bits/stdc++.h>
using namespace std;
char a[10100][10100];
int main () {
string s;
cin >> s;
int len = s.length();
for (int i = 1; i <= len; i++) {
char ch = s[len - i];
if (ch == '0') {
for (int j = 1; j <= len - i + 2; j++) a[i][j] = '*', a[2 * len - i][j] = '*';
}
else {
for (int j = 1; j <= len - i + 2; j++) a[i][j] = '-', a[2 * len - i][j] = '-';
}
for (int j = len - i + 3; j <= len + 1; j++) {
if (a[i - 1][j] == '-' || a[i - 1][j] == '|') a[i][j] = '|', a[2 * len - i][j] = '|';
else a[i][j] = '*', a[2 * len - i][j] = '*';
}
}
for (int i = 1; i <= 2 * len - 1; i++) {
for (int j = 1; j <= len + 1; j++) {
cout << a[i][j];
}
cout << endl;
}
return 0;
}
D:
一眼dz,感觉是一道签到题
结果是一道思维题,我的贪心贪错了,
但是我的贪心正确率很高,导致我空想根本找不出来什么反例,
后来对拍了一下才找到了一组反例,然后又换了一个方法切掉了,感觉难度在M题附近浮动
我的思路:
先读取数据,判断是不是无穷(左右都至少要有一个0才不是无穷)
再对于左边快速排序一下,升序考虑每一条边
经过排序,左边即红色法术的法力消耗是递增的,依次遍历,对于第i张法术,我们把它的红色法力值作为答案红色法力值的备选,它的红色法术消耗大于上面所有法术,那么还要保证前面的法术无法使用,那么答案的蓝色法术值一定要小于前面所有法术的蓝色法术值,因为我们是遍历的,所以可以逐步更新维护蓝色法术值的最小值,直到找到一张蓝色法术值为0的法术(我们知道它一定存在),那么后面的法术值都不能作为答案了,就可以跳出循环。
#include <bits/stdc++.h>
using namespace std;
pair<int, int> a[5010];
bool compare(pair<int, int> a, pair<int, int> b) {
if (a.first == b. first) return a.second < b.second;
return a.first < b.first;
}
int main () {
int t; cin >> t;
while(t--) {
int ok1 = 1, ok2 = 1;
int n, res;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].first >> a[i].second;
if (a[i].first == 0) ok1 = 0;
if (a[i].second == 0) ok2 = 0;
}
if (ok1 || ok2) cout << "INF" <<endl;
else {
sort(a + 1, a + n + 1, compare);
int minn = a[1].second;
res = a[1].first + a[1].second - 2;
for (int i = 1; i <= n; i++) {
res = max(res, a[i].first + minn - 2);
minn = min(minn, a[i].second);
if (minn == 0) break;
}
cout << res << endl;
}
}
return 0;
}
标答:
#include<bits/stdc++.h>
using namespace std;
int n;
struct node
{
int x,y;
}a[5010];
bool cmp(node _1,node _2)
{
if(_1.x!=_2.x)
return _1.x<_2.x;
return _1.y<_2.y;
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
cin >> a[i].x >> a[i].y;
bool ok1=0,ok2=0;
for(int i=1;i<=n;i++)
{
if(a[i].y==0)
ok1=1;
if(a[i].x==0)
ok2=1;
}
if(!ok1||!ok2)
{
cout << "INF" << endl;
}
int small=1000000000;
int ans=0;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
small=min(small,a[i].y);
if(small!=0)
ans=max(ans,small-1+a[i+1].x-1);
}
cout << ans << endl;
return 0;
}
L:
纯思维题,因为要询问中位数,如果把1和n交换位置,不会影响中位数的选择,就是说这两种全排列都符合。
特判n==1时是唯一确定的。
#include <bits/stdc++.h>
using namespace std;
int main () {
int n, m;
cin >> n >> m;
if (n == 1) cout << "YES" << endl;
else cout << "NO" << endl;
return 0;
}
H:
计算几何(也许?),题本身不难,但是有笨蛋把两点式方程算错了导致WA了很久~
算角度用余弦定理,有时候因为浮点数精度问题会导致cos值大于1或者小于-1,这时候acos函数会返回nan,我们需要将范围外的余弦置为1或-1
然后大约有怎么几种情况:
1.守门员划水,一点都没挡住。
2.前锋打假赛,不可能进。
3.守门员防守范围和射门范围之间有重合,但不是包含关系。
4.守门员防守范围包含于射门范围之内。
根据这四点分类讨论即可,
因为数据最大1e7,所以开了long double,不知道有没有用。
#include <bits/stdc++.h>
#define double long double
using namespace std;
double dis (double x1, double y1, double x2, double y2) {
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}
double k (double x1, double y1, double x2, double y2) {
if (x1 == x2) return x1;
else if (y1 == y2) return 1;
else return (x2 * y1 - x1 * y2) / (y1 - y2);
}
int main () {
int t; cin >> t;
double w, x1, y1, x2, y2, d;
while (t--) {
cin >> w >> x1 >> y1 >> x2 >> y2 >> d;
double d1 = dis(x1, y1, -w, 0), d2 = dis(x1, y1, w, 0), d3 = dis(x1, y1, x2 - d, y2), d4 = dis(x1, y1, x2 + d, y2);
double k3 = k(x1, y1, x2 - d, y2), k4 = k(x1, y1, x2 + d, y2);
double res1 = (d1 + d2 - 4 * w * w) / sqrt(d1 * d2) * 0.5, res2 = (d3 + d4 - 4 * d * d) / sqrt(d3 * d4) * 0.5;
if (res1 > 1) res1 = 1.0;
if (res1 < -1) res1 = -1.0;
if (res2 > 1) res2 = 1.0;
if (res2 < -1) res2 = -1.0;
double ans1 = acos(res1), ans2 = acos(res2);
if (y1 < y2 || (y1 == y2 && (x2 - d > x1 || x2 + d < x1))) {
printf("%.10Lf\n", ans1);
}
else if (y1 == y2 || (k4 >= w && k3 <= -w)) printf("%.10lf\n", 0.0);
else if (k3 >= w || k4 <= -w) {
printf("%.10Lf\n", ans1);
}
else if (k4 >= w && k3 <= w && k3 >= -w) {
d4 = d2;
double d5 = dis(x2 - d, y2, w, 0);
res2 = (d3 + d4 - d5) / sqrt(d3 * d4) * 0.5;
if (res2 > 1) res2 = 1.0;
if (res2 < -1) res2 = -1.0;
ans2 = acos(res2);
printf("%.10Lf\n", ans1 - ans2);
}
else if (k3 <= -w && k4 >= -w && k4 <= w) {
d3 = d1;
double d5 = dis(x2 + d, y2, -w, 0);
res2 = (d3 + d4 - d5) / sqrt(d3 * d4) * 0.5;
if (res2 > 1) res2 = 1.0;
if (res2 < -1) res2 = -1.0;
ans2 = acos(res2);
printf("%.10Lf\n", ans1 - ans2);
}
else printf("%.10Lf\n", ans1 - ans2);
}
return 0;
}
I:
本题还行,需要进行一些思考:
反正我就硬贪心,贪就完了!
分为这几种情况:
1.没车,全部走路。
2.车比人多,全部骑车。
3.有车且车比人少:
根据一个简单的贪心,取得答案时每个人骑车的时间,路程一定要相等,因此我们可以找到单位人骑车和走路的路程之比,
如果m % n == 0, 那么总共有为m / n 批车, 每人可以骑1批车, 骑车时间与总路程之比为 n : m
思考一下之后, m % n != 0时也是这个比例(我感觉不太好表述就不证了)
因此我们就可以得到结果
想明白以后程序挺简单的
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main () {
ll t, n, m, l, v1, v2;
cin >> t;
long double ans;
while (t --) {
cin >> m >> n >> l >> v1 >> v2;
if (m <= n) {
ans = (long double)l / v2;
printf("%.7Lf\n", ans);
}
else {
if (n == 0) {
ans = (long double) l / v1;
printf("%.7Lf\n", ans);
}
else {
ans = (long double) l / m * n / v2 + (long double) l / m * (m - n) / v1;
printf("%.7Lf\n", ans);
}
}}
return 0;
}
G:
中规中矩的dp,我直接用状态机做了,
状态有不持有bit币和持有bit币两种
要达到最大收益,xzm学长每次交易都要交易1bit
定义一个f[i][j][k]:
经历i个时刻交易j次,是否持有股票时的收益
写一下状态转移:
初始状态:
f[0][j][0], f[0][j][1] 不可能存在,因为没有经历过时刻就交易过了,不能转移,设为负无穷
f[0][0][0] = 0
目标:
max(a[i][j][0])
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define INF 0x3f3f3f3f
double a[1010];
double f[1010][1010][2];
int main () {
int n, k;
cin >> n >> k;
rep(i, 1, n) cin >> a[i];
double ans = 0;
rep(j, 0, k) f[0][j][0] = f[0][j][1] = -INF;
f[0][0][0] = 0;
rep(i, 1, n) {
rep(j, 0, k) {
f[i][j][0] = f[i - 1][j][0];
f[i][j][1] = f[i - 1][j][1];
if (j) {
f[i][j][0] = max(f[i][j][0], f[i - 1][j - 1][1] + a[i]);
f[i][j][1] = max(f[i][j][1], f[i - 1][j - 1][0] - a[i]);
}
ans = max(ans, f[i][j][0]);
}
}
printf("%.2lf\n", ans);
return 0;
}
B
数组模拟不太会,OPT看错方法了,写了一个错的deque,然后感觉不太会,就去看题解去了。
FIFO: 队列的性质,直接开一个队列执行操作即可。
rep(i, 1, n) {
cin >> a[i];
if (!v1[a[i]]) {
cnt1 ++;
v1[a[i]] = 1;
if (q1.size() && q1.size() == k) {
v1[q1.front()] = 0; q1.pop(); q1.push(a[i]);
}
else q1.push(a[i]);
}
}
LRU:
淘汰最长时间未访问的界面,可以用一个经过修改的队列:
如果有一个元素即将入列且队列里面有这个元素,那么它的访问时间是需要更新的,但是又不想去交换顺序什么的,操作过于麻烦,就可以把这个元素直接入队,并打上标记,并把k++,即让队列最大长度加一,当要执行出队操作时,把队前有标记的元素直接出队,k--,去掉标记。
memset(v2, 0, sizeof v2);
memset(v3, 0, sizeof v3);
int k2 = k;
rep(i, 1, n) {
if (!v2[a[i]]) {
cnt2 ++;
v2[a[i]] = 1;
if (q2.size() && q2.size() >= k) {
// cout << k << "1" << endl;
while (q2.size() && v3[q2.front()]) {
k--; v3[q2.front()]--; q2.pop();
}
v2[q2.front()] = 0; q2.pop(); q2.push(a[i]);
}
else q2.push(a[i]);
}
else {
k++;
q2.push(a[i]);
v3[a[i]] ++;
}
}
k = k2;
OPT不会用队列做,deque也不会,题解是用数组模拟写的,还没看懂
总之,可以得到结论OPT永远是最少的。
F:
(脏牧狂喜)
背包
因为随从数量较少,可以单独对每一个随从讨论,让它成为狂乱攻击对象,攻击一个随从就要杀死它,否则没有意义,我们就可以把被攻击的随从的攻击力乘上被消灭所需要的攻击次数,就是消灭这个随从对于攻击随从的伤害。
把这个更新完以后,就是个01背包,直接做就行
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(x) (x) & (-x)
#define fs first
#define sc second
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define PII pair<int,int>
int n;
struct node{
int v;
int c;
}a[1010];
int f[10010], x[1010], y[1010];
bool compare (node a, node b) {
return a.v < b.v;
}
int main () {
cin >> n;
rep(i, 1, n) cin >> x[i] >> y[i];
int res = 0;
rep(i, 1, n) {
int sumc = 0, sumv = 0, m = 0;
rep(j, 1, n) {
if (i == j) continue;
m++;
a[m].v = x[j];
a[m].c = y[j] % x[i] == 0 ? y[j] / x[i] : y[j] / x[i] + 1;
a[m].c *= x[j];
sumc += a[m].c;
sumv += a[m].v;
}
if (sumc < y[i]) {
res = max(res, sumv);
continue;
}
sort(a + 1, a + n + 1, compare);
memset(f, 0, sizeof f);
int ans = 0;
rep(k, 1, m) {
rep(j, a[k].c - a[k]. v, y[i]) {
int p = j - a[k].c + a[k].v;
if (p >= 0) ans = max(ans, f[p] + a[k].v);
}
per(j, a[k].c, y[i] - 1) f[j] = max(f[j], f[j - a[k].c] + a[k]. v);
}
ans = max(ans, f[y[i] - 1]);
ans += x[i];
res = max(res, ans);
}
rep(i, 1, n) res -= x[i];
cout << -res << endl;
return 0;
}
:
计划写完F就不写了,C是一个容易TLE的大模拟,K是一个不好转化的数论.
本文作者:misasteria
本文链接:https://www.cnblogs.com/misasteria/p/16240404.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步