打比赛千万千万千万不要上头(来自因死磕数论A题两小时而痛失两道最短路(压根连题面都没读)最终五题结尾的蒟蒻的赛后反思)
A.你也喜欢数学吗
真的一点都不喜欢数学好吧
先打表找规律,(找了二十分钟发现的规律,写了两小时最后发现只能过38%就离谱)
佬们说一眼看出来是k * (k + 1) * (k + 2) / 6, 不晓得楞个看出来的
不过即使看出来,也要先处理k,、k + 1和k + 2,不然会爆long long
冗长而难以理解的代码如下
#include <iostream>
using namespace std;
typedef unsigned long long ll;
const int mod = 1000000007;
ll ans;
ll quick_mul(ll a, ll b, ll mod)
{
ll res = 0;
while(b)
{
if(b & 1)
{
res += a;
res %= mod;
}
a <<= 1;
a %= mod;
b >>= 1;
}
return res;
}
int main()
{
ll k, x, y, z;
scanf("%lld", &k);
x = k, y = k + 1, z = k + 2;
if(x % 2 == 0)
{
x /= 2;
}
else if(y % 2 == 0)
{
y /= 2;
}
if(x % 3 == 0)
{
x /= 3;
}
else if(y % 3 == 0)
{
y /= 3;
}
else
{
z /= 3;
}
ans = quick_mul(quick_mul(x, y, mod), z, mod);
printf("%lld", ans);
return 0;
}
E.动物朋友
前缀和+二分(ps:记得开long long, 不然会像我一样WA5发不知道哪错了)
循环遍历每一点
二分搜索从当前点开始是否存在连续的符合题意的区间,如果连续,则对于该区间的左端 l , 右端 r 有:
s[r] - s[l - 1] == m (s为前缀和数组)
#include <iostream>
using namespace std;
const int N = 1e6 + 20;
int n, m, ans;
long long q[N], s[N];
bool check(long long x)
{
int l = 0, r = n, mid;
while(l <= r)
{
mid = l + r >> 1;
if(s[mid] == x) return true;
else if(s[mid] > x) r = mid - 1;
else l = mid + 1;
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i ++)
{
scanf("%lld",&q[i]);
s[i] = s[i - 1] + q[i];
}
for(int i = 0; i < n; i ++)
{
if(check(s[i] + m))
{
ans ++;
}
}
printf("%d",ans);
return 0;
}
F.松鼠排序
枚举
依次从头枚举每个位置,若当前位置上坚果的大小与下标不同,则将该坚果交换至与其大小相同的下标处,重复上述操作直至当前位置上坚果大小与下标相同,枚举下一个位置
#include <iostream>
using namespace std;
const int N = 1e5 + 20;
int q[N];
int main()
{
int n, ans = 0;
scanf("%d",&n);
for(int i = 1; i <= n; i ++)
{
scanf("%d",&q[i]);
}
int i = 1;
while(i < n)
{
while(q[i] != i)
{
swap(q[i], q[q[i]]);
ans ++;
}
i ++;
}
printf("%d",ans);
return 0;
}
G.Reverse
签到题(WA两发是怎么有脸说这是签到题的)
要注意cnt > x时,先把x的值赋给y,不然就会像我一样WA两发(x表示最长连续的1的长度,y表示次长连续1的长度)
#include <iostream>
#include <string>
using namespace std;
string s;
int main()
{
int n, x = 0, y = 0, cnt = 0;
scanf("%d",&n);
cin >> s;
for(auto i : s)
{
if(i - '0')
{
cnt ++;
}
else
{
if(cnt > x)
{
y = x;
x = cnt;
}
else if(cnt > y)
{
y = cnt;
}
cnt = 0;
}
}
if(cnt > x)
{
y = x;
x = cnt;
}
else if(cnt > y)
{
y = cnt;
}
printf("%d",x + y);
return 0;
}
H.迷宫探险
最短路(bfs)
bfs模板套一下,不过要注意从发射器起跳时,发射器的落点与发射器到起点的距离相同
另外,注意从发射器跳到发射器的这种情况,check()函数用来处理这种情况
judge()函数用来判断边界问题(避免代码宽度过大,不方便查看)
#include <unordered_map>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N = 3010;
typedef pair<int, int> PII;
unordered_map<int, int> mp;
queue<PII> q;
char g[N][N];
int n, m, d[N][N];
bool judge(int x, int f)
{
if(f)
{
if(x >= 1 && x <= n) return true;
}
else
{
if(x >= 1 && x <= m) return true;
}
return false;
}
void check(int x, int y)
{
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
for(int i = 0; i < 4; i ++)
{
int a = x + dx[i] * mp[x * 10000 + y], b = y + dy[i] * mp[x * 10000 + y];
if(judge(a, 1) && judge(b, 0))
{
if(g[a][b] == '.' && d[a][b] == -1)
{
d[a][b] = d[x][y];
q.push({a, b});
}
else if(g[a][b] == '*' && d[a][b] == -1)
{
d[a][b] = d[x][y];
check(a, b);
}
}
}
}
void bfs()
{
memset(d, -1, sizeof(d));
q.push({1, 1});
int x, y, dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
d[1][1] = 0;
while(!q.empty())
{
PII t = q.front();
q.pop();
for(int i = 0; i < 4; i ++)
{
x = t.first + dx[i], y = t.second + dy[i];
if(judge(x, 1) && judge(y, 0))
{
if(g[x][y] == '.' && d[x][y] == -1)
{
d[x][y] = d[t.first][t.second] + 1;
q.push({x, y});
}
else if(g[x][y] == '*' && d[x][y] == -1)
{
d[x][y] = d[t.first][t.second] + 1;
check(x, y);
}
}
}
}
}
int main()
{
int k, x, y, z;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
{
cin >> g[i][j];
}
}
scanf("%d",&k);
while(k --)
{
scanf("%d%d%d",&x,&y,&z);
if(z)
{
mp[x * 10000 + y] = z;
}
}
bfs();
printf("%d",d[n][m]);
return 0;
}
J.合唱比赛
农大竟然有合唱比赛,建议把高清视频发B站供我欣赏
区间左端点:我给它的分是最低分的时候, 此时最高分为题给最高分
区间右端点:我给它的分是最高分的时候, 此时最低分为题给最低分
综上,我压根无法左右比赛结果,我就是个菜狗,呜呜呜~
#include <iostream>
using namespace std;
int main()
{
int n;
double z, x = 0, y = 101, ans = 0;
scanf("%d",&n);
for(int i = 1; i <= n; i ++)
{
scanf("%lf",&z);
ans += z;
x = max(x, z);
y = min(y, z);
}
printf("%lf %lf", (ans - x) / (n - 1), (ans - y) / (n - 1));
return 0;
}
K.以撒和隐藏房间
枚举每一个点即可
注意题面要求是与三个普通房间相邻,不是至少三个
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, g[N][N];
bool check(int x, int y)
{
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}, cnt = 0;
for(int i = 0; i < 4; i ++)
{
if(x + dx[i] < 1 || x + dx[i] > n || y + dy[i] < 1 || y + dy[i] > m) continue;
if(g[x + dx[i]][y + dy[i]] == 2) return false;
if(g[x + dx[i]][y + dy[i]] == 1) cnt ++;
}
if(cnt == 3) return true;
return false;
}
int main()
{
bool f = 0;
int ans = 0;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m ; j ++)
{
scanf("%1d",&g[i][j]);
}
}
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
{
if(g[i][j] == 0)
{
if(check(i, j))
{
f = 1;
ans ++;
}
}
}
}
if(f)
{
puts("YES");
printf("%d\n", ans);
}
else puts("NO");
return 0;
}