一、题目报告
比赛中第一题10分,第二题60分,第三题50分(1组数据),第四题10分;比赛后AK。
二、赛中概况
前一个小时觉得第一题要算法,先打的第二题,打了一个小时没想到正解思路,就打了暴力开下一题。第一题20分钟写完(最后爆10了),第三题一眼dp不会写
(烦)写了dfs,第四题直接不会,输入样例骗了10分。(一道题的正解都没想出来的考生是屑)
三、解题报告
T1.交替出场(alter)
题目情况
比赛时10pts。
题目大意
给定一个01字符串,求其中01子串个数
题目解析
直接枚举每个子串会超时,所以我们枚举左端点和右端点,并且枚举右端点时,只要发现不匹配就直接break,节省复杂度
正解代码
#include<bits/stdc++.h>
using namespace std;
string s;
int main(){
cin>>s;
s=' '+s;
int ans=0,len=s.size();
for(int i=1;i<len;i++){
ans++;
for(int j=1+i;j<=len;j++){
if(s[j]+s[j-1]=='0'+'1'){ans++;}
else break;
}
}
cout<<ans;
return 0;
}
T2.翻翻转转(filp)
题目情况
比赛时60pts。
题目大意
字符串是逐位取反后拼接在后的串。你需要求(?的第个字符是什么。
题目解析
x<=1e9,这样的数据范围只能用O(),用logn复杂度的算法中可以推出二分。
正解代码
#include<bits/stdc++.h>
using namespace std;
int x;
void fun(int l,int r,int p){
if(l==x&&r==x){
cout<<(1==p)<<endl;return;
}
int mid=(l+r)/2;if(x<=mid)fun(l,mid,p);
else fun(mid+1,r,-p);
}
int main(){
int t;
cin>>t;
while(t--){
cin>>x;
fun(1,1<<30,1);
}
return 0;
}
T3.方格取数(square)
题目情况
比赛时50pts。
题目大意
NOIP方格取数,但有步数限制
题目解析
本题需要用dp进行完成,重点是推导状态转移方程。
正解代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 210;
ll dx[2] = {1, 0}, dy[2] = {0, 1};
ll n, m, k, a[N][N], dp[N][N][N][2], ans = -1e18;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> k;
for (ll i = 1; i <= n; i++)
for (ll j = 1; j <= m; j++)
cin >> a[i][j];
memset(dp, -0x3f, sizeof(dp));
dp[1][1][0][0] = dp[1][1][0][1] = a[1][1];
for (ll x = 1; x <= n; x++)
for (ll y = 1; y <= m; y++)
for (ll l = 0; l < k; l++)
for (ll d = 0; d <= 1; d++) {
if (dp[x][y][l][d] < -1e18)continue;
for (ll nd = 0; nd <= 1; nd++) {
ll nx = x + dx[nd], ny = y + dy[nd];
if (nx < 1 || nx > n || ny < 1 || ny > m)continue;
if (d != nd)
dp[nx][ny][1][nd] = max(dp[nx][ny][1][nd], dp[x][y]
[l][d] + a[nx][ny]);
else if (l < k - 1)
dp[nx][ny][l + 1][nd] =max(dp[nx][ny][l + 1][nd], dp[x][y][l][d] +
a[nx][ny]);
}
}
for (ll l = 0; l < k; l++)
for (ll d = 0; d <= 1; d++)
ans = max(ans, dp[n][m][l][d]);
if (ans == -1e18)
cout << "No Answer!";
else
cout << ans;
return 0;
}
T4.圆圆中的方方(round)
题目情况
比赛时10pts。
题目大意
给你矩形的四顶点和一个⚪的圆心和半径,求正方形与⚪重合的面积
题目解析
数学题
在sub2中,,根据勾股定理可以看出r>m,r>n,则圆完全覆盖矩形,答案为n*m
在sub3中,,则矩形完全覆盖圆,答案为
正解代码
#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1), eps = 1e-6;
double n, m, x, y, r;
double calc(double n, double m, double r) {
if (n > m)
swap(n, m);
if (n < eps || m < eps)
return 0;
if (r <= n)
return 0.25 * pi * r * r;
else if (r <= m) {
double tt = sqrt(r * r - n * n);
double res = n * tt / 2.0;
double ang = pi / 2 - acos(n / r);
res += ang / 2 * r * r;
return res;
} else if (r <= sqrt(n * n + m * m)) {
double t1 = sqrt(r * r - n * n), t2 = sqrt(r * r - m * m);
double res = n * t1 / 2.0 + m * t2 / 2.0;
double ang = pi / 2 - acos(n / r) - acos(m / r);
res += ang / 2 * r * r;
return res;
} else
return n * m;
}
int main() {
cin >> n >> m >> x >> y >> r;
cout << fixed << setprecision(10)
<< calc(x, y, r) + calc(x, m - y, r) + calc(n - x, y, r) +
calc(n - x, m - y, r)
<< endl;
return 0;
}
四、总结
本场考试中,我的思路没有跟上,错过了一些掌握的算法,复杂度没有计算好,导致第一题失误,仍需努力