要是有题目FST了就重新写
A
签到
#include<bits/stdc++.h>
using namespace std;
int T;
long long n,k,ans;
int main()
{
cin>>T;
while(T--)
{
cin>>n>>k,ans=0;
while(n)
{
ans+=n%k;
ans++,n/=k;
}
cout<<ans-1<<endl;
}
}
B
暴力模拟,记得打标记和开long long,注意特判
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+7;
int T,top;
char str[101];
ll ans,st[N];
int main()
{
scanf("%d",&T);
st[0]=1;
while(T--)
{
scanf("%s",str);
if(str[0]=='a')
{
if(st[top]==-1)ans=-1;
else ans+=st[top];
if(st[top]==-1||ans>=(1ll<<32)){puts("OVERFLOW!!!");return 0;}
}
else if(str[0]=='f')
{
ll x;scanf("%I64d",&x);
if(st[top]==-1)st[top+1]=-1;
else st[top+1]=x*st[top];
top++;
if(st[top]>=(1ll<<32))st[top]=-1;
}
else top--;
}
cout<<ans;
}
C
我写个O(nlogn)复杂了,实际上是签到题,我还写个二分
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int n,k,pos,a[N];
bool check(int d)
{
for(int l=1,r=1;l<=n;l++)
{
while(r<n&&a[r+1]-a[l]<=2*d)r++;
if(r-l+1>k){pos=a[l]+d;return 1;}
}
return 0;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int L=0,R=a[n]-a[1],mid,ans=R;
while(L<=R)
{
mid=L+R>>1;
if(check(mid))ans=mid,R=mid-1;
else L=mid+1;
}
printf("%d\n",pos);
}
}
D
发现是k段后缀和,其中[1,n]必须得选,其余[2,n]...[n,n]选最大的k段即可。
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
int n,k,a[N];
long long ans,s[N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
if(n==1){printf("%d",a[1]);return 0;}
for(int i=n;i;i--)s[i]=s[i+1]+a[i];
sort(s+2,s+n+1);
reverse(s+2,s+n+1);
for(int i=1;i<=k;i++)ans+=s[i];
cout<<ans;
}
E
首先求出每个位置仅用一条线段能走到哪,这个显然可以线段树覆盖(实际上排序也许,不过线段树太好想了)。然后愉快地倍增即可。
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int N=5e5+7;
int n,m,all=5e5,lazy[N<<2],mx[N<<2],fa[N][20];
void modify(int rt,int v){lazy[rt]=max(lazy[rt],v),mx[rt]=max(mx[rt],v);}
void pushdown(int rt)
{
if(!lazy[rt])return;
modify(rt<<1,lazy[rt]),modify(rt<<1|1,lazy[rt]);
lazy[rt]=0;
}
void update(int L,int R,int v,int l,int r,int rt)
{
if(L<=l&&r<=R){modify(rt,v);return;}
pushdown(rt);
int mid=l+r>>1;
if(L<=mid)update(L,R,v,lson);
if(R>mid)update(L,R,v,rson);
mx[rt]=max(mx[rt],mx[rt<<1|1]);
}
void query(int l,int r,int rt)
{
if(l==r){fa[l][0]=max(l,mx[rt]);return;}
pushdown(rt);
int mid=l+r>>1;
query(lson),query(rson);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=n;i++)scanf("%d%d",&x,&y),update(x,y,y,0,all,1);
query(0,all,1);
for(int j=1;j<=19;j++)
for(int i=0;i<=all;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
while(m--)
{
int x,y,ans=0;scanf("%d%d",&x,&y);
for(int i=19;~i;i--)if(fa[x][i]<y)x=fa[x][i],ans+=(1<<i);
if(fa[x][0]<y)puts("-1");
else printf("%d\n",ans+1);
}
}
F
我们可以从后向前扫,然后找以i为起点的答案。显然区间内不能有相同的数字,于是可以记录nxt[i]数组表示从i位置向后延展到nxt[i]-1处数字均互不相同,这个显然线性维护。由于区间要求值为[1,len],所以很容易发现越短的区间最大值越小,所以从后向前扫时,仅需维护一个单调递减的队列,然后对于队列中相邻的数,根据位置和该位置的值,建立树状数组即可。复杂度O(nlogn)
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+7;
int n,qs,qe,a[N],b[N],c[N],nxt[N],q[N];
long long ans;
void add(int x,int v){if(x>0)while(x<=n)c[x]+=v,x+=x&-x;}
int ask(int x){int ret=0;while(x)ret+=c[x],x-=x&-x;return ret;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
nxt[n+1]=n+1;
for(int i=1;i<=n;i++)b[i]=n+1;
for(int i=n;i;i--)
{
nxt[i]=min(nxt[i+1],b[a[i]]),b[a[i]]=i;
while(qs<qe&&a[q[qe-1]]<=a[i])
{
if(qs+1<qe)add(q[qe-2]-a[q[qe-1]],-1);
qe--;
}
q[qe++]=i;
if(qs+1<qe)add(q[qe-2]-a[q[qe-1]],1);
while(qs<qe&&q[qs]>=nxt[i])
{
if(qs+1<qe)add(q[qs]-a[q[qs+1]],-1);
qs++;
}
ans+=ask(n)-ask(i-1);
if(nxt[i]-a[q[qs]]>=i)ans++;
}
cout<<ans;
}
G
首先显然分层DP,朴素的O(n2k)DP相信考过提高组的人都会,然后考虑如何优化。看着不大的数据范围,想到可能是O(nklogn)这种奇怪的复杂度,然后看着就想到直接分治。分治后,记录从分治点向两边的前缀/后缀最大值,可以跑一遍two-pointer,然后发现每个位置的答案是一次函数,然后就可以写个单调栈就行了。
#include<bits/stdc++.h>
using namespace std;
const int N=20086,inf=0x3f3f3f3f;
struct line{
int k,b;
line(){}
line(int _k,int _b){k=_k,b=_b;}
int get(int x){return k*x+b;}
}st[N];
int n,k,top,a[N],f[N],g[N],pre[N],suf[N];
bool cmp(line a,line b,line c){return 1ll*(a.k-b.k)*(c.b-a.b)<=1ll*(a.k-c.k)*(b.b-a.b);}
void insert(line x)
{
while(top&&x.k>=st[top].k)x.b=min(x.b,st[top].b),top--;
while(top>1&&cmp(st[top-1],st[top],x))top--;
st[++top]=x;
}
int calc(int x)
{
if(!top)return inf;
int l=1,r=top;
while(l<r)
{
int m=l+r>>1;
if(st[m].get(x)<=st[m+1].get(x))r=m;else l=m+1;
}
return st[l].get(x);
}
void solve(int l,int r)
{
if(l==r)return;
int m=l+r>>1;
solve(l,m),solve(m+1,r);
suf[m+1]=0;for(int i=m;i>=l;i--)suf[i]=max(suf[i+1],a[i]);
pre[m]=0;for(int i=m+1;i<=r;i++)pre[i]=max(pre[i-1],a[i]);
top=0;
for(int i=r,j=l;i>m;i--)
{
while(j<=m&&suf[j+1]>=pre[i])if(g[j++]<inf)insert(line(suf[j],g[j-1]-(j-1)*suf[j]));
f[i]=min(f[i],calc(i));
}
top=0;
for(int i=m+1,j=m;i<=r;i++)
{
while(j>=l&&suf[j+1]<=pre[i])if(g[j--]<inf)insert(line(j+1,g[j+1]));
f[i]=min(f[i],calc(-pre[i])+i*pre[i]);
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),pre[i]=max(pre[i-1],a[i]);
for(int i=1;i<=n;i++)f[i]=pre[i]*i;
for(int i=2;i<=k;i++)memcpy(g,f,sizeof g),memset(f,0x3f,sizeof f),solve(1,n);
printf("%d",f[n]);
}
result:rank11,rating+=159,精准的没超过rating=2210的小号。
来源:oschina
链接:https://my.oschina.net/u/4307191/blog/3509694