牛客 小白111 20250307
牛客 小白111 20250307
https://ac.nowcoder.com/acm/contest/102742
A:
题目大意:给定三个 \(v\) 三个 \(a\) ,模拟田忌赛马的策略判断是否获胜
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
using namespace std;
int main()
{
int v[3],a[3];
cin>>v[0]>>v[1]>>v[2];
cin>>a[0]>>a[1]>>a[2];
sort(v,v+3);
sort(a,a+3);
if (a[1]>v[0]&&a[2]>v[1]) cout<<"Yes";
else cout<<"No";
return 0;
}
排序,选 \(a\) 中两个最大的和 \(v\) 中两个最小的比
B:
题目大意:给定字符串 如果有连续的偶数个 \(n\) 可以使这个连续子串变为 \(y\) ,判断最后至多有多少个 \(y\)
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
using namespace std;
int main()
{
int n;
cin>>n;
vector<char> a(n+10);
for (int i=1;i<=n;i++) cin>>a[i];
int sum=0;
for (int i=1;i<=n;i++){
if (a[i]=='y') sum++;
if (a[i]=='n'&&a[i+1]=='n'){
sum++;
i++;
}
}
cout<<sum;
return 0;
}
贪心策略,当有两个连续的 \(n\) ,那么就即可转变为 \(y\)
C:
题目大意:有 \(n\) 条字符串,可以选取其中一条删去,连续且相同的字符串的最多条数
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
using namespace std;
int dp[100010][2];
int main()
{
int n;
cin>>n;
vector<string> s(n+5);
int ans=1;
for (int i=1;i<=n;i++)
cin>>s[i];
for (int i=1;i<=n;i++) dp[i][1]=dp[i][0]=1;
for (int i=2;i<=n;i++){
for (int j=0;j<=1;j++){
if (s[i]==s[i-1])
dp[i][j]=dp[i-1][j]+1;
if (i>=3&&s[i]==s[i-2]&&j==1)
dp[i][j]=max(dp[i][1],dp[i-2][0]+1);
ans=max(ans,dp[i][j]);
}
}
cout<<ans;
return 0;
}
我比较笨,上来就写个DP,\(dp_{i,j}\) 表示前 \(i\) 个字符串删去 \(j\) 条字符的连续且相同的字符串的最多条数
事实上可以利用滑动窗口的方法解决,虽然时间复杂度不如DP
map<string,int> mp;
int l=1;
int ans=0;
for (int r=1;r<=n;r++){
mp[s[r]]++;
while(mp.size()>2||min(mp.begin()->second,mp.rbegin()->second)>1&&mp.size()>1){
mp[s[l]]--;
if (mp[s[l]]==0) mp.erase(s[l]);
l++;
}
if (mp.size()==1) ans=max(ans,r-l+1);
else ans=max(ans,r-l);
}
cout<<ans;
mp 记录滑动窗口中不同的字符串以及它的数量
向右滑动后,新加入窗口的字符串可以对状态有三种改变
- 窗口内的字符串种类数多于 \(2\)
- 窗口内仍然最多只有两个字符串,其中数量最少的字符串的个数多于 \(1\)
- 窗口内仍然最多只有两个字符串,且数量最少的字符串的个数少于等于 \(1\)
其中前两个状态不满足题目要求,我们最多只能删去窗口内的一条字符串
while(mp.size()>2||min(mp.begin()->second,mp.rbegin()->second)>1&&mp.size()>1){
mp[s[l]]--;
if (mp[s[l]]==0) mp.erase(s[l]);
l++;
}
并且如果移动左指针时,对应的字符串数量变为 \(0\) ,需要立即将这个字符串从 mp 内擦去
D:
题目大意:
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
using namespace std;
int n,m,T;
int a[1010][1010];
int g[1010][1010];
int dp[1010][1010];
int ans;
int main()
{
memset(g,0x3f,sizeof g);//没有障碍的位置可以看作在极长的时间后才生成障碍
cin>>n>>m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
cin>>a[i][j];
cin>>T;
for (int i=1;i<=T;i++){
int x,y,v;
cin>>x>>y>>v;
g[x][y]=v;
}
dp[1][1]=a[1][1];
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (i==1&&j==1) continue;
if (i+j-1>g[i][j]) continue;
if (i-1>0&&dp[i-1][j])
dp[i][j]=max(dp[i-1][j]+a[i][j],dp[i][j]);
if (j-1>0&&dp[i][j-1])
dp[i][j]=max(dp[i][j-1]+a[i][j],dp[i][j]);
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
ans=max(ans,dp[i][j]);
cout<<ans;
return 0;
}
一开始用BFS搜,因为每个点不止入队一次,所以空间爆炸
改用DP,类似过河卒的做法,加入的随时间生成的障碍
又因为每个时刻只能走一个,且只能向下或向右,所以可以通过坐标计算时间 \(t=i+j-1\)
从 \((1,1)\) 出发,开始递推DP,状态转移方程为
因为在收集金币时,必须从已经走过的路径上转移,所以需要保证 \(dp_{i-1,j},dp_{i,j-1}\) 都不为 \(0\)
考虑随时间生成的障碍和边界情况,添加两条规则
if (i==1&&j==1) continue;
if (i+j-1>g[i][j]) continue;
E:
题目大意:

#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define Trd int T;cin>>T;while (T--)solve();
#define LLinf 9e18;
#define Iinf 2e9
#define LL long long
#define Lc p<<1
#define Rc p<<1|1
#define lc(x) tr[x].ch[0]
#define rc(x) tr[x].ch[1]
using namespace std;
LL n,m,k;
int main()
{
cin>>n>>m>>k;
vector<LL> a(n+1,0),pre=a;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
LL ans=0;
for (int i=1;i<=n;i++){
int L=upper_bound(a.begin(),a.end(),k+a[i])-a.begin();
int R=lower_bound(a.begin(),a.end(),m+a[i]+k+1)-1-a.begin();
int l=i+1;
int r=lower_bound(a.begin(),a.end(),m+a[i]-k+1)-1-a.begin();
ans+=1ll*(r-l+1)*(m+a[i]-k+1)-(pre[r]-pre[i]);
if (R>=L) ans+=1ll*(R-L+1)*(m+a[i]+k+1)-(pre[R]-pre[L-1]);
}
cout<<ans;
return 0;
}
推柿子题
设 \(d=a_j-a_i\),高为 \(h\) ,那么 \(k=\lvert d-h\rvert\),考虑两种情况
-
\(k=d-h\implies h=d-k\) 可以构成矩形的数量为
\[\sum_{i=1}^{n}\sum_{j=i+1}^{n}(m-h+1)=\sum_{i=1}^{n}\sum_{j=i+1}^{n}(m-(a_j-a_i-k)+1) \]此外还需要保证
\[a_j-a_i>k\ \ ,\ \ m-(a_j-a_i-k)+1>0\\ \implies a_j>k+a_i\ \ ,\ \ a_j<m+a_i+k+1 \] -
\(k=h-d\implies h=d+k\) 可以构成矩形的数量为
\[\sum_{i=1}^{n}\sum_{j=i+1}^{n}(m-h+1)=\sum_{i=1}^{n}\sum_{j=i+1}^{n}(m-(a_j-a_i+k)+1) \]此外还需要保证
\[a_j-a_i>0\ \ ,\ \ m-(a_j-a_i+k)+1>0\\ \implies a_j>a_i\ \ ,\ \ a_j<m+a_i-k+1 \]
设满足第一种情况的 \(j\in[L,R]\) ,第二种情况的 \(j\in[l,r]\),可以通过二分查找实现
最后整理公式得到
其中的 \(\sum a_j\) 可以通过前缀和预处理,算法总时间复杂度为 \(O(n\log n)\)
int L=upper_bound(a.begin(),a.end(),k+a[i])-a.begin();
int R=lower_bound(a.begin(),a.end(),m+a[i]+k+1)-a.begin()-1;
//不减一查找的是 a_j >= m+a_i+k+1 的第一个元素,减一后才在范围内
int l=i+1;
int r=lower_bound(a.begin(),a.end(),m+a[i]-k+1)-a.begin()-1;
//不减一查找的是 a_j >= m+a_i-k+1 的第一个元素,减一后才在范围内
并且只有当 \(r>l,R>L\) 时答案才能正确累加
ans+=1ll*(r-l+1)*(m+a[i]-k+1)-(pre[r]-pre[i]);//r一定大于l,因为m-k+1>0
if (R>=L) ans+=1ll*(R-L+1)*(m+a[i]+k+1)-(pre[R]-pre[L-1]);

浙公网安备 33010602011771号