a2dc2d7d-eea2-4d21-b15c-e870b4e8e1be
按照过题人数顺序
A: World Final? World Cup! (I)
难度:签到
题意:a和b轮流罚球共十次询问到第几次的时候分出胜负(接下来的每球的罚球结果不影响比赛胜负)
做法:直接按题意模拟
代码:
void solve()
{
char s[15];
scanf("%s", s + 1);
int a{}, b{};
for(int i = 1; i <= 10; i++)
{
if(i & 1)
{
if(s[i] == '1')
a++;
if(a > (10 - i + 1)/ 2 + b || b > (10 - i)/ 2 + a)
{
//cout << a << ' ' << b << '\n';
cout << i << '\n';
return ;
}
}
else
{
if(s[i] == '1')
b++;
if(a > (10 - i + 1)/ 2 + b || b > (10 - i)/ 2 + a)
{
cout << i << '\n';
return ;
}
}
}
if(a == b)
cout << "-1" << '\n';
else
cout << "10" << '\n';
return ;
}
L:本题主要考察了运气
难度:签到
挨个试出的答案
C:现在是,学术时间 (I)
难度:签到
题意:共有n个教授n个论文, 定义H指数"该教授发表的所有论文中,有至少H篇论文的引用量大于等于H" 求的最大值。
做法: 显然一个教授一篇论文的时候最大。
代码:
void solve()
{
int n{}, ans{};
cin >> n;
rep(i, 1, n)
{
int x;
cin >> x;
if(x) ans++;
}
cout << ans << '\n';
}
K:本题主要考察了dp
难度:简单
题意:一个长度为n的01串其中1的个数恰好为m个, 定义一个长度为3的自区间其中恰好2个1为一个坏区间, 求给定01串最少的坏区间个数
做法: 找规律发现最优秀的区间为1001001001, 把01串前半部分都改成最优秀的区间, 后半部分只会有这两种情况: 1001011和 1001111 不难发现剩下多少个1就会产生多少个坏区间。
代码:
void solve()
{
int n, m;
cin >> n >> m;
if(n == m) cout << n - 2 << '\n';
else if((n - 1) / 3 + 1>= m) cout << 0 << '\n';
else cout << m - (n - m) / 2 - 1 << '\n';
}
D:现在是,学术时间 (II)
难度:简单
题意:给出点(X,Y)和点(Xp,Yp), 以(Xp,Yp)为一个顶点做一个矩形和以(X, Y)(0, 0)为顶点的矩形的交集和并集的比的最大值。
做法:不难发现最优解是以矩形的其中一个顶点和p点作新矩形。用dx和dy数组储存四个点的情况然后循环找最大值即可。
代码:
void solve()
{
double x, y, xp, yp;
cin >> x >> y >> xp >> yp;
double s = x * y;
double maxx = 0;
double dx[] = {0, 0, x, x};
double dy[] = {0, y, 0, y};
rep(i, 0, 3)
{
double s1 = abs(dx[i] - xp) * abs(dy[i] - yp);
double s2 = s + s1;
double s3 = abs(min(x, max(dx[i], xp)) - max(0.0, min(dx[i], xp))) * abs(min(y, max(dy[i], yp)) - max(0.0, min(dy[i], yp)));
s2 -= s3;
double res = s3 / s2;
maxx = max(maxx, res);
}
cout << maxx << '\n';
}
H:本题主要考察了DFS
难度:简单
题意:给出一个拼图, 缺少其中一块,给出其他几块拼图的形状(0代表该边是平的, 1代表改边是凹的, 2代表该边是凸的)求剩下一块的权值(权值为 10 -X+Y X为凹的数目, Y为凸的数目)
做法:像正常拼图一样凹凸数目肯定会匹配,所以只需要记录所有拼图块的X和Y 最后直接输出
10 - Y + X 即可, X和Y会自动抵消。
代码:
void solve()
{
int n;
cin >> n;
string s;
int x{}, y{};
rep(i, 1, n * n - 1)
{
cin >> s;
rep(j, 0, 3)
{
if(s[j] == '1') x++;
else if(s[j] == '2') y++;
}
}
cout << 10 - y + x << '\n';
}
M:本题主要考察了找规律
难度:中等
题意:有m份仙贝和n个朋友, 若当前剩下x个仙贝并给以为朋友y个仙贝,收获改个朋友好感度y/x, 求和所有朋友的好感度之和最大为多少(初始都为0)
做法:想到了dp, 设i为第i个朋友, j为送出了j个仙贝。状态转移方程如下
f[i][j] = max(f[i][j], f[i - 1][j - k] + k * 1.0 / (m - j + k));
或者设i为第i个朋友, j为手中还剩j个仙贝。状态转移方程如下
f[i][j] = max(f[i][j], f[i - 1][j + k] + k * 1.0 / (j + k));
代码:
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<double> >f(n + 1, vector<double>(m + 1, 0));
rep(i, 1, n)
{
rep(j, 1, m)
{
rep(k, 1, j)
{
f[i][j] = max(f[i][j], f[i - 1][j - k] + k * 1.0 / (m - j + k));
}
}
}
cout << fixed << setprecision(10) << f[n][m] << '\n';
}
G:鸡格线
难度:中等
题意你有一个长为nnn的数组aaa,你需要支持以下两种操作:
1、输入l,r,kl,r,kl,r,k,对区间[l,r]中所有数字执行ai=f(ai)操作k次(式中等号表示赋值操作),之中f(x)=round(10),round为四舍五入函数。
2、输出当前数组所有数字的和。
你需要正确处理m次这样的操作。
做法:
有三种不同做法, 第一种是直接用线段树维护, 现在还没补这种做法。
第二种和第三种的思想相同, 首先观察函数f(x)会发现函数收敛, 打表发现, 最后都会收敛于0, 99, 100, 所以当函数f(x) == x时就可以不再对x执行操作, 可以用并查集和set来维护下一个需要操作的x所在的位置即可。
代码:
用set维护的方法
void solve()
{
int n, m;
cin >> n >> m;
ll sum{};
set<int>st;
vector<int>a(n + 1);
st.insert(n + 1); //插入一个n+1方便使用;
rep(i, 1, n)
{
cin >> a[i];
sum += a[i];
if(f(a[i]) != a[i]) st.insert(i); //set里存的是下一个可以操作的x的下标;
}
while(m--)
{
int op;
cin >> op;
if(op == 1)
{
int l, r, k;
cin >> l >> r >> k;
int pos = l; // pos初始值为l;
while(1)
{
int nex = *st.lower_bound(pos); //找出set中第一个大于等于pos的下标;
if(nex > r) break;
for(int i = 1; i <= min(20, k); i++)
{
sum -= a[nex];
sum += f(a[nex]);
a[nex] = f(a[nex]);
}
if(f(a[nex]) == a[nex])
{
st.erase(nex); //把不能操作的x删掉;
}
pos = nex + 1;
}
}
else
{
cout << sum << '\n';
}
}
}
用并查集维护的方法:
void solve()
{
int n, m;
cin >> n >> m;
vector<int>a(n + 2);
vector<int>fa(n + 2);
iota(fa.begin(), fa.end(), 0);
ll sum{};
rep(i, 1, n)
{
cin >> a[i];
sum += a[i];
}
function<int(int)> find = [&](int x)
{
return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
};
while(m--)
{
int op;
cin >> op;
if(op == 1)
{
int l, r, k;
cin >> l >> r >> k;
for(int i = l; i <= r; i = find(i + 1)) //跳到下一个需要操作的x的位置
{
for(int j = 1; j <= k; j++)
{
ll x = f(a[i]);
sum -= a[i] - x;
if(x == a[i])
{
fa[i] = find(i + 1); //如果a[i]不能操作了,
//把a[i]和下一个需要操作的x合并,
//方便查询需要操作的x的位置。
break;
}
a[i] = x;
}
}
}
else cout << sum << '\n';
}
用线段树维护的方法: 待补