题意:有q个区间,区间范围为1-n,要求q-2个区间所能覆盖的最大的范围。
思路:先把所有区间都加上1,得到总范围sum,然后暴力枚举两个区间,sum减去这两个区间所能得到的值的和答案max一下即可,可以用点为1和点为2的前缀和数组快速求出删除两个区间后的总范围。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
int l[maxn],r[maxn],a[maxn],n,ans,res;
int sum[maxn][4];
int main()
{
int q;
scanf("%d%d",&n,&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l[i],&r[i]);
a[l[i]]++,a[r[i]+1]--;
}
for(int i=1;i<=n;i++)
{
a[i]+=a[i-1];
if(a[i])res++;
for(int j=0;j<3;j++)
sum[i][j]=sum[i-1][j];
if(a[i]==1)sum[i][1]++;
if(a[i]==2)sum[i][2]++;
}
for(int i=1;i<q;i++)
for(int j=i+1;j<=q;j++)
{
int ql=max(l[i],l[j]);
int qr=min(r[i],r[j]);
if(ql>qr)
{
int t=sum[r[i]][1]-sum[l[i]-1][1];
t+=sum[r[j]][1]-sum[l[j]-1][1];
ans=max(ans,res-t);
}
else
{
int t=sum[qr][2]-sum[ql-1][2];
int ll=min(l[i],l[j]);
int rr=max(r[i],r[j]);
t+=sum[ql][1]-sum[ll-1][1];
t+=sum[rr][1]-sum[qr][1];
ans=max(ans,res-t);
}
}
cout<<ans;
}
题意:有n个东西有初始电量ai,每秒耗电bi,持续k秒种,每个东西的电量都不能为负数,你可以每秒选择某一个东西充电ans,求最小的ans。
思路:首先二分ans,接下来如何去check呢?很多人写了O(n)的check,实在是巧妙,我水平垃圾一点就写个nlogn的check吧,用线段树保存每个东西当前电量所能工作的时间的区间最小值,然后k秒每秒给线段树中最小值去充电即可,当线段树区间最小值小于0时就不合法。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+5;
ll mn[maxn*4],v[maxn*4],a[maxn],b[maxn];
int n,k,tag[maxn*4];
void build(int o,int l,int r)
{
tag[o]=0;
if(l==r)
{
mn[o]=a[l]/b[l];
v[o]=a[l]%b[l];
return;
}
int ls=o*2,rs=o*2+1,m=(l+r)/2;
build(ls,l,m);
build(rs,m+1,r);
mn[o]=min(mn[ls],mn[rs]);
}
void qu(int o,int l,int r,ll res)
{
int ls=o*2,rs=o*2+1,m=(l+r)/2;
if(l==r)
{
mn[o]+=res/b[l];
v[o]+=res%b[l];
mn[o]+=v[o]/b[l];
v[o]%=b[l];
return;
}
if(mn[ls]<=0&&mn[rs]<=0)return;
if(mn[ls]<mn[rs])qu(ls,l,m,res);
else qu(rs,m+1,r,res);
mn[o]=min(mn[ls],mn[rs]);
}
int ok(ll res)
{
build(1,1,n);
for(int i=1;i<k;i++)
{
qu(1,1,n,res);
if(mn[1]-i+1<=0)return 0;
}
return 1;
}
int main()
{
ll l=0,r=0,m;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
r=max(r,b[i]*k-a[i]);
}
if(!ok(r))puts("-1"),exit(0);
while(l<r)
{
m=(l+r)/2;
if(ok(m))r=m;
else l=m+1;
}
printf("%lld\n",l);
}
题意:有cnti个i,要求这些数所能组成的一个最大的数ans,ans<=w。
思路:暴搜,我们发现8个1可以用1个8代替,因此每个数从最大数量递减搜7次(我搜3次也能过)即可,复杂度7^8。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll w,a[10],ans;
void dfs(int x,ll res)
{
if(!x)
{
ans=max(ans,res);
return;
}
for(ll i=3,num=min(a[x],(w-res)/x);i;i--,num--)
dfs(x-1,res+max(0ll,num*x));
}
int main()
{
cin>>w;
for(int i=1;i<=8;i++)cin>>a[i];
dfs(8,0);
cout<<ans;
}
题意:给你一个字符串,每次可以把连续相同的字串删除,求最小次数把字符串删完。
思路:区间dp,设d[ i ][ j ]为 [ i , j ]的字串删除完的最小次数,很显然d[ i ][ j ]=min(d[ i ][ j ],d[ i ][ k ]+d[ k+1 ][ j ]+s[i]==s[k+1] || s[i]==s[j] || s[k]==s[k+1] || s[k]==s[j]?-1:0),如果s[i]==s[j],d[ i ][ j ]=min(d[ i ][ j ],d[i+1][ j-1 ]+1),还有两个很显然的转移方程就不写了。
#include<bits/stdc++.h>
using namespace std;
int d[501][501],n;
char a[501];
int dfs(int l,int r)
{
if(l>r)return 0;
if(l==r)return 1;
if(d[l][r])return d[l][r];
int res=1e9;
for(int i=l;i<r;i++)
{
int tmp=dfs(l,i)+dfs(i+1,r);
if(a[l]==a[i+1]||a[l]==a[r]||a[i]==a[i+1]||a[i]==a[r])
tmp--;
res=min(res,tmp);
}
if(a[l]==a[r])
res=min(res,dfs(l+1,r-1)+1);
if(a[l]==a[l+1])
res=min(res,dfs(l+1,r));
if(a[r]==a[r-1])
res=min(res,dfs(l,r-1));
return d[l][r]=res;
}
int main()
{
scanf("%d%s",&n,a+1);
printf("%d\n",dfs(1,n));
}
题意:给你一个长度为n的序列,让你求所有长度为k的连续子序列的"最长递增长度"(这个递增指的是题目要求的递增,不同于常识的那个)。
思路:对于每个数ai,用单调栈求出右边第一个比它大的数aj,然后连边aj-->ai,然后将序列转换成树结构,接下来对这棵树跑dfs序,然后用最大值线段树保存每个节点的深度,假设求出了[ 1 k ]的答案mx[1],接下来我们右边移一下,先将第一个数的值在线段树中减去无穷大,然后把第k+1个数在树结构中的子树节点全部+1,就可以了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int mx[maxn*4],tag[maxn*4],cnt,sz[maxn],a[maxn],id[maxn];
vector<int>G[maxn];
stack<int>s;
void dfs(int u)
{
sz[u]=1;
id[u]=++cnt;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
dfs(v);
sz[u]+=sz[v];
}
}
void pushdown(int o,int ls,int rs)
{
if(tag[o]!=0)
{
tag[ls]+=tag[o],tag[rs]+=tag[o];
mx[ls]+=tag[o],mx[rs]+=tag[o];
tag[o]=0;
}
}
void up(int o,int l,int r,int ql,int qr,int v)
{
int m=(l+r)/2,ls=o*2,rs=o*2+1;
if(l!=r)
pushdown(o,ls,rs);
if(l>=ql&&r<=qr)
{
mx[o]+=v;
tag[o]+=v;
return;
}
if(ql<=m)up(ls,l,m,ql,qr,v);
if(qr>m)up(rs,m+1,r,ql,qr,v);
mx[o]=max(mx[ls],mx[rs]);
}
int main()
{
int n,k,ans=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=n;i;i--)
{
while(!s.empty()&&a[i]>=a[s.top()])s.pop();
if(!s.empty())
G[s.top()].push_back(i);
s.push(i);
}
for(int i=n;i;i--)
if(!id[i])dfs(i);
for(int i=1;i<=k;i++)
up(1,1,n,id[i],id[i]+sz[i]-1,1);
printf("%d",mx[1]);
for(int i=k+1;i<=n;i++)
{
up(1,1,n,id[i-k],id[i-k],-10000000);
up(1,1,n,id[i],id[i]+sz[i]-1,1);
printf(" %d",mx[1]);
}
}