2023牛客寒假训练营1补题
K
分析
思维题,先考虑100100100....这样一个序列能接受最多的1的情况
如果有多的1,就先从后面开始放
赛时是一样的思路,但是细节方面没处理好
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
vector<int> s;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
int p = n - m;
while(m || p){
if(m) s.push_back(1),m--;
if(p) s.push_back(0),p--;
if(p) s.push_back(0),p--;
}
int ans = 0;
for(int i=1;i<n-1;i++)
if(s[i] + s[i-1] + s[i+1] >=2)
ans++;
cout << ans << endl;
return 0;
}
D
分析
基本上算一眼结论题,四个区域分别讨论即可,赛时在纠结K,没有细看该题
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
void solve(){
int x,y,xp,yp;
cin >> x >> y >> xp >> yp;
if(xp <= x && yp <= y){
int sum = x * y;
int maxx = 0;
maxx = max(maxx,xp*yp);
maxx = max(maxx,(y-yp)*xp);
maxx = max(maxx,(x-xp)*(y-yp));
maxx = max(maxx,(x-xp)*yp);
double res = (double)maxx/(double)sum;
cout << res << endl;
}
else{
if(xp >= x && yp >= y){
int sum1 = x * y;
int sum2 = xp * yp;
int jq = x*y;
int m = sum1 + sum2 - jq;
double res = (double)jq/(double)m;
cout << res << endl;
}
else if(xp >= x && yp < y){
int sum1 = x * y;
int sum2 = xp * yp;
int jq = x*yp;
int m = sum1 + sum2 - jq;
double res = (double)jq/(double)m;
sum2 = xp*(y-yp);
jq = x*(y-yp);
m = sum1 + sum2 - jq;
res = max(res,(double)jq/(double)m);
cout << res << endl;
}
else if(xp < x && yp >= y){
int sum1 = x * y;
int sum2 = xp * yp;
int jq = xp*y;
int m = sum1 + sum2 - jq;
double res = (double)jq/(double)m;
sum2 = (x-xp)*yp;
jq = (x-xp)*y;
m = sum1 + sum2 - jq;
res = max(res,(double)jq/(double)m);
cout << res << endl;
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
M
解析
dp,利用几个样例可以知道
假设(i,j)是用i个仙贝分给j个人,那么(i,j)的状态可以由(i-k,j-1)转移过来(即第i个人分k个仙贝)
这样一来转移方程和状态就可以确定 \(dp[i][j] = max(dp[i-k][j-1] + k*1.0/i,dp[i][j])\)
刚开始写的时候把n,m看反了,不想改后面的了,就swap了一下
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
double dp[505][505];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(int x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
swap(n,m);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
for(int k = 0; k <= i; k++){
dp[i][j] = max(dp[i-k][j-1] + k*1.0/i,dp[i][j]);
}
}
}
cout << fixed << setprecision(6);
cout << dp[n][m] << endl;
return 0;
}
G
解析
通过样例可以算出每个数最多经过不超过20次操作一定能收敛成一个定值(超过100的逐渐变小,小于100的逐渐变大)
可以用set维护数组的下标
每当有一个数达到收敛值时,就erase
时间复杂度为 \(O(k*nlogn)\)
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e5 + 5;
int n,m,a[N],ans;
set<int> st;
int f(int x){
return round(sqrt(x)*10);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i];
ans += a[i];
if(f(a[i]) != a[i]){
st.insert(i);
}
}
st.insert(n+1);
int op,l,r,k;
while(m--){
cin>>op;
if(op==1){
cin >> l >> r >> k;
int pos=l;
while(1){
int rpk = *st.lower_bound(pos);
if(rpk>r) break;
for(int i = 1;i <= min(k,(int)20); i++){
ans -= a[rpk];
a[rpk] = f(a[rpk]);
ans += a[rpk];
}
if(f(a[rpk]) == a[rpk]){
st.erase(rpk);
}
pos = rpk + 1;
}
}
else{
cout << ans << endl;
}
}
return 0;
}