- 吴易繁 的博客
七月暑期集训DAY05
- @ 2024-7-12 19:20:53
A. 小田的最大价值
题目类型:排序加分类讨论
思路
- 先将数组排序。
- 若最大值减最小值>k,则输出最大值。
- 若最大值减最小值<=k,则输出次大值。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N];
int main(){
freopen("max.in","r",stdin);
freopen("max.out","w",stdout);
int k,n;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
if(a[n]-a[1]>k) cout<<a[n];
else cout<<a[n-1];
return 0;
}
本题代码已AC,下一次继续保持。
B. 小田的交换数字
题目类型:字符串
思路
- 如果想得到a*b的结果最小,那就要使a与b的差最大。
- 所以遍历0至n,若a[i]>b[i]交换a[i]与b[i]的值。
- 最后只要将答案对998244353取模就好了。
代码
#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int mod=998244353;
int s1,s2;
signed main(){
freopen("mul.in","r",stdin);
freopen("mul.out","w",stdout);
int n;
string a,b;
cin>>n;
cin>>a>>b;
for(int i=0;i<n;i++){
s1=(s1*10+max(a[i],b[i])-'0')%mod;
s2=(s2*10+min(a[i],b[i])-'0')%mod;
}
cout<<(int)((s1%mod)*(s2%mod))%mod;
return 0;
}
这道题我在写的时候不知道怎么将a与b相乘,下一次要把事情想的简单点。
C. 小田的气球真好看
题目类型:双指针或DP
思路
DP
- 初始状态为f[1]=1,flag[a[1]]=1。
- 状态转移为:
- if(j==0) f[i]=min(i,f[i-1]+1)。
- else if(i-j<=k) f[i]=min(f[j]+i-j,f[i-1]+1)。
- else if(i-j>k) f[i]=min(i-j,f[i-1]+1)。
双指针
- 枚举起点l,以这个为起点,找到最后一个满足条件的r,这个区间有多长,就有多少个子区间。
- 用标记数组,标记0到l之间的子序列数量。
- 要更新标记数组 。
- 当l往右走时,如果值是记录在标记数组的最后一个位置,则需要消除。
注意
不管是双指针还是DP,都要用long long。
代码
DP
#include<bits/stdc++.h>
using namespace std;
long long f[100010],flag[100010],a[100010];
int main(){
freopen("balloon.in","r",stdin);
freopen("balloon.out","w",stdout);
long long n,k,ans=0,j;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
f[1]=1;
flag[a[1]]=1;
for(long long i=2;i<=n;i++){
j=flag[a[i]];
if(j==0) f[i]=min(i,f[i-1]+1);
else if(i-j<=k) f[i]=min(f[j]+i-j,f[i-1]+1);
else if(i-j>k) f[i]=min(i-j,f[i-1]+1);
flag[a[i]]=i;
}
for(long long i=1;i<=n;i++) ans+=f[i];
cout<<ans;
return 0;
}
双指针
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k,a[N],flag[N];
long long cnt=0;
int main(){
freopen("balloon.in","r",stdin);
freopen("balloon.out","w",stdout);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
int l=1,r=0;
while(l<=n){
while(r<n&&(r+1-flag[a[r+1]]<=k||!flag[a[r+1]])) r++,flag[a[r]]=r;
cnt+=r-l+1;
if(flag[a[l]]==l) flag[a[l]]=0;
l++;
}
cout<<cnt;
return 0;
}
这道题目在写的时候想到了双指针,但没写出来,就放弃了。所以以后不能轻易放弃。
D. 表达式求值
题目类型:栈
思路
- 这道题目需要用一个逻辑栈与一个符号栈来做。
- 若s[i]='t'或'f',压入逻辑栈。
- 其他的压入符号栈。
- 若遇到右括号,遍历得出括号里的答案。
- 最后看逻辑栈栈头元素,若逻辑栈栈头元素为't',输出true,若逻辑栈栈头元素为'f',输出false。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
freopen("expr.in","r",stdin);
freopen("expr.out","w",stdout);
int t;
cin>>t;
while(t--){
string s;
cin>>s;
stack<char> a;
stack<char> op;
for(int i=0;i<s.size();i++){
if(s[i]=='t'||s[i]=='f') a.push(s[i]);
if(s[i]==',') op.push(s[i]);
if(s[i]=='&'||s[i]=='|'||s[i]=='!') op.push(s[i]),op.push('(');
if(s[i]==')'){
int ans=1;
while(op.top()!='(') op.pop(),ans++;
op.pop();
if(op.top()=='!'){
for(int i=1;i<=ans;i++){
if(a.top()=='t') a.pop(),a.push('f');
else a.pop(),a.push('t');
}
}
else if(op.top()=='&'&&ans>1){
bool flag=1;
for(int i=1;i<=ans;i++){
if(a.top()=='f') flag=0;
a.pop();
}
if(flag) a.push('t');
else a.push('f');
}
else{
bool flag=0;
for(int i=1;i<=ans;i++){
if(a.top()=='t') flag=1;
a.pop();
}
if(flag) a.push('t');
else a.push('f');
}
op.pop();
}
}
if(a.top()=='t') cout<<"true"<<endl;
else cout<<"false"<<endl;
}
return 0;
}
这道题只想着一个栈做,下次要想着用两个栈做。
D. 表达式求值
题目类型:栈
思路
- 这道题目需要用一个数字栈与一个符号栈来做。
- 若s[i]='t'
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
freopen("expr.in","r",stdin);
freopen("expr.out","w",stdout);
int t;
cin>>t;
while(t--){
string s;
cin>>s;
stack<char> a;
stack<char> op;
for(int i=0;i<s.size();i++){
if(s[i]=='t'||s[i]=='f') a.push(s[i]);
if(s[i]==',') op.push(s[i]);
if(s[i]=='&'||s[i]=='|'||s[i]=='!') op.push(s[i]),op.push('(');
if(s[i]==')'){
int ans=1;
while(op.top()!='(') op.pop(),ans++;
op.pop();
if(op.top()=='!'){
for(int i=1;i<=ans;i++){
if(a.top()=='t') a.pop(),a.push('f');
else a.pop(),a.push('t');
}
}
else if(op.top()=='&'&&ans>1){
bool flag=1;
for(int i=1;i<=ans;i++){
if(a.top()=='f') flag=0;
a.pop();
}
if(flag) a.push('t');
else a.push('f');
}
else{
bool flag=0;
for(int i=1;i<=ans;i++){
if(a.top()=='t') flag=1;
a.pop();
}
if(flag) a.push('t');
else a.push('f');
}
op.pop();
}
}
if(a.top()=='t') cout<<"true"<<endl;
else cout<<"false"<<endl;
}
return 0;
}
这道题只想着一个栈做,下次要想着用两个栈做。
E. 小W去冒险
题目类型:搜索
思路
这道题目其实就是DFS模版改一下即可。
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,dy[6]={0,1,0,-1},dx[6]={1,0,-1,0},a[110][110];
int cnt=0;
char c;
bool st[110][110];
void dfs(int x,int y){
st[x][y]=1;
a[x][y]=0;
for(int i=0;i<4;i++){
int nx=dx[i]+x,ny=dy[i]+y;
if(!st[nx][ny]&&a[nx][ny]!=0&&nx>=1&&ny>=1&&nx<=n&&ny<=m){
dfs(nx,ny);
}
}
return;
}
int main(){
freopen("ymx.in","r",stdin);
freopen("ymx.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c;
a[i][j]=c-'0';
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]!=0) {
dfs(i,j);
cnt++;
}
}
}
cout<<cnt;
return 0;
}
这道题在写的时候模版写出来了,但有一个地方没有改,下一次还是要根据题目做出改变。
F. 检查总结
题目类型:DP
思路
- 初始状态为f[n]=1,f[n+1]=0。
- 状态转移为:
- if(i+a[i]<=n) f[i]=min(f[i+1]+1,f[i+a[i]+1]);
- else f[i]=f[i+1]+1。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],f[N];
int main(){
freopen("summary.in","r",stdin);
freopen("summary.out","w",stdout);
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
f[n]=1;
f[n+1]=0;
for(int i=n;i>=1;i--){
if(i+a[i]<=n) f[i]=min(f[i+1]+1,f[i+a[i]+1]);
else f[i]=f[i+1]+1;
}
cout<<f[1];
return 0;
}
DP还没有学过,老师说以后会单独开一节课来讲DP。