第三题
我称之为找规律题,当然用二分也行
很容易就得到一个公式--》a[i]-v*b[i]<=b(0<=b<b[i])
即B ≤ A/V < B+1---》A/(B+1) < V ≤ A/B
cpp
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int main()
{
cin>>n;
int maxv=1e9,minv=1;
while(n--)
{
int a,b;
cin>>a>>b;
int curmax=a/b;
int curmin=a/(b+1)+1;
minv=max(minv,curmin);
maxv=min(maxv,curmax);
}
cout<<minv<<' '<<maxv<<endl;
return 0;
}
二分法
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010;
int n;
int a[N], b[N];
bool check(int x)
{
if(x == 0) return false;
for(int i = 0; i < n; i++)
{
if(b[i] == 0) {
if(a[i] >= x) return false;
} else {
if(a[i] / x != b[i]) return false;
}
}
return true;
}
int main()
{
int minv, maxv=0x3f3f3f3f;
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> a[i] >> b[i];
maxv=min(a[i]/b[i],maxv);
}
// 找最小值
int l = 0, r =maxv+1; // 扩大范围
while(l + 1 < r)
{
int mid = (l + r) >> 1;
if(check(mid)) r = mid;
else l = mid;
}
minv = r;
cout << minv << ' ' <<maxv<< endl;
return 0;
}
第四题
这个题目很明显的是dfs暴力枚举了--》也就是枚举出全排列看有没有符合的
枚举出飞机降落的不同顺序看看是否有可以降落成功的序列,如果可以降落成功--》yes
cpp
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=15;
int n;
int t[N],d[N],l[N];
int p[N];
bool st[N];
bool found;
bool check()
{
int last=0;
for(int i=0;i<n;i++)
{
int idx=p[i];
int start=max(last,t[idx]);
if(start>t[idx]+d[idx])return false;
last=start+l[idx];
}
return true;
}
void dfs(int x)
{
if(x==n)
{
if(check())
{
found=true;
}
return;
}
for(int i=0;i<n;i++)
{
if(!st[i])
{
st[i]=true;
p[x]=i;
dfs(x+1);
st[i]=false;
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>t[i]>>d[i]>>l[i];
}
memset(st,false,sizeof st);
found=false;
dfs(0);
if(found)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
第五题
这个题目我是用暴力解决的--》大部分tle了(一般来说写出暴力dfs基本上就能推导出动态规划,但这个题目我还是没有推出来,动态规划还是联系的太少了!!!)
暴力dfs枚举方法:最直接的想法:每个数可以选 或不选,枚举所有子序列,检查是否是接龙数列。
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
typedef long long ll;
int n;
ll a[100010];
int res=0x3f3f3f3f;
int fenjie(int x)
{
while(x>=10)
{
x/=10;
}
return x;
}
void dfs(int x,int cnt,int last)
{
if(x>n)
{
res=min(res,cnt);
return;
}
//不选
dfs(x+1,cnt+1,last);
//选
//如果是第一个直接选
if(last==0)
{
dfs(x+1,cnt,x);
}
else if((a[last]%10==fenjie(a[x])))//满足要求
{
dfs(x+1,cnt,x);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
dfs(1,0,0);
cout<<res<<endl;
return 0;
}
第六题
这个题目我当时看到以为是一个简单的dfs找连通量的数量问题,但是一看还有环什么乱七八糟的,看了看我不会做我就把这个当找连通量数量来做了,没想到还拿了6分(嘻嘻🤭)
第七题
这个题目其实不难,用暴力直接双重循环也能解决但是肯定是超时(但是也能拿到不少分)
我们看这个题目其实就是遍历这个字符串,当找到c1时在遍历后面的有几个c2且满足条件就加上,一直到遍历结束(条件不满足)
那么怎么进行优化呢
就可以用前缀和的方式--》计算出某位置之后的c2的个数
注意的是:这个其实我们计算的是后缀和从后面开始,因为我们加的是在某个位置之后的等于c2的数量
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=500010;
string s;
int k;
char c1,c2;
int sum[N];
int main()
{
cin>>k;
cin>>s;
int n=s.size();
cin>>c1>>c2;
for(int i=n-1;i>=0;i--)
{
sum[i]=sum[i+1]+(s[i]==c2);
}
ll cnt=0;
for(int i=0;i<n;i++)
{
if(s[i]==c1&&i+k-1<n)
{
cnt+=sum[i+k-1];
}
}
cout<<cnt<<endl;
return 0;
}
第八题
这道题目用了最小堆+双向链表
看到这道题目当中有查找最小值的左右两端的元素--->就可以想到链表
但是我当时没想到用了暴力自然而然就tle了
大概步骤就是:建立最小堆、双链表--》每次删除最小值--》将最小值左右两端的加上最小值--》最后输出
cpp
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=500010;
int n,k;
ll a[N];
int pre[N],nxt[N];
bool deleted[N];
struct node{
int idx;
ll val;
bool operator<(const node& other) const{
if(val!=other.val)return val>other.val;
return idx>other.idx;
}
};
priority_queue<node> pq;
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
pre[i]=i-1;
nxt[i]=i+1;
pq.push({i,a[i]});
}
pre[1]=0;
nxt[n]=0;
int cnt=0;
while(cnt<k)
{
node cur=pq.top();
pq.pop();
int idx=cur.idx;
//如果被删除或者值已经被修改--》无效
if(deleted[idx]||cur.val!=a[idx])continue;
deleted[idx]=true;
int l=pre[idx];
int r=nxt[idx];
//如果有前驱/后继
if(l!=0)
{
a[l]+=a[idx];
pq.push({l,a[l]});
nxt[l]=r;
}
if(r!=0)
{
a[r]+=a[idx];
pq.push({r,a[r]});
pre[r]=l;
}
cnt++;
}
for(int i=1;i<=n;i++)
{
if(!deleted[i])
{
cout<<a[i]<<' ';
}
}
cout<<endl;
return 0;
}