A 简单交换
水题。。
B--折木棍
解法来自群友
f[i][j]:第i个木棍拆成最大值为j使前面满足条件的最小拆法次数
贪心得到一个这种拆法的木棍最小值X和次数S
f[i][j]=max(f[i-1][k]+s) k<=x其实就是 每个木棍a[i] 枚举最大值是len (最右边是len) 以及最左边: a[i]%len 计算最小拆法:s=a[i]/len+((a[i]%len==0)?0:1)-1
按照每个位置都是len 最左边的数要么是a[i]%len 要么是len 那如何计算 最左边的合法的最大值呢?pos+1个数 平均a[i]就好了 k=a[i]/(pos+1)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL a[3005], f[3005][3005];
int main() {
int n; scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%lld", &a[i]);
}
memset(f, 7, sizeof(f));
for(int i=0; i<3005; i++) f[0][i]=0;
for(int i=1; i<=n; i++){
for(int len=1; len<3005; len++){
if(len>a[i]){
f[i][len]=f[i][len-1];
continue;
}
LL pos=a[i]/len+((a[i]%len==0)?0:1)-1;//按照mi len len len 切的次数pos
LL mi=((a[i]%len==0)?len:(a[i]%len));
//pos*len+mi==a[i]
LL x=(pos*len+mi)/(pos+1);//切pos刀有pos+1个位置,a[i]平均分给pos+1个位置就是最大合法的值x
//printf("mi:%lld x:%lld\n",mi,x);
f[i][len]=f[i-1][x]+pos;
f[i][len]=min(f[i][len], f[i][len-1]);
//cout<<i<<" "<<len<<" "<<f[i][len]<<endl;
}
}
LL ans=1<<30;
for(int i=1; i<=a[n]; i++){
ans=min(ans, f[n][i]);
}
printf("%lld\n", ans);
return 0;
}
/*
5
3 5 13 9 12
ans:1
5
5 4 3 2 1
ans:
*/
C--优惠券
对a排序,b[i]在a中二分即可。
D--站得高 看得远
经典单调栈题
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
int a[N],ans[N],n,m,l[N],r[N];
int main()
{
int _;cin>>_;while(_--)
{
scanf("%d",&n);
rep(i,1,n) scanf("%d",&a[i]);
stack<int>sta;
rep(i,1,n) l[i]=r[i]=i;
for(int i=1;i<=n;++i){
if(sta.size()==0) sta.push(i);
else{
while(sta.size()&&a[i]>=a[sta.top()]) {
sta.pop();
}
if(sta.size()) l[i]=sta.top()+1;
else l[i]=1;
sta.push(i);
}
}
while(sta.size()) sta.pop();
for(int i=n;i;--i){
if(sta.size()==0) sta.push(i);
else{
while(sta.size()&&a[i]>=a[sta.top()]) {
sta.pop();
}
if(sta.size()) {
r[i]=sta.top()-1;
}
else r[i]=n;
sta.push(i);
}
}
rep(i,1,n)
{
printf("%d ",r[i]-l[i]);
}
puts("");
}
}