2021.12.19 eleveni的刷题记录


2021.12.19 eleveni的刷题记录

0. 本次记录有意思的题

0.1 每个点恰好经过一次并且求最小时间

P2469 [SDOI2010]星际竞速

https://www.luogu.com.cn/problem/P2469

费用流

0.2 把数字序列转化为01串

AT2165 [AGC006D] Median Pyramid Hard

https://www.luogu.com.cn/problem/AT2165

二分

1. 基础算法

1.1 二分

https://www.luogu.com.cn/problem/AT2165

#include
#include
#include
#include
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const int N=2e5+10;
int n,a[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline bool check(int maxn){
	for(int i=0;imaxn&&a[n-i-1]>maxn)||(a[n+i]>maxn&&a[n+i+1]>maxn))return false;
	}
	return a[1]<=maxn;
}

signed main(){
	IOS;
	cin>>n;
	for(int i=1;i<=n*2-1;i++)cin>>a[i];
	int L=1,R=n*2-1,mid,ans;
	while(L>1;
		if(check(mid))R=ans=mid;
		else L=mid+1;
	}
	cout<

https://www.luogu.com.cn/problem/P4343

记得把右边界开大!!!!

#include
#include
#include
#include
#include
#include
#include
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define int long long
const int N=1e5+10;
int n,m,num[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline bool check1(int maxn){
	int now=0,cnt=0;
	for(int i=1;i<=n;i++){
		now+=num[i];
		if(now<0)now=0;
		if(now>=maxn)++cnt,now=0;
	}
	return cnt>=m;
}
inline bool check2(int maxn){
	int now=0,cnt=0;
	for(int i=1;i<=n;i++){
		now+=num[i];
		if(now<0)now=0;
		if(now>=maxn)++cnt,now=0;
	}
	return cnt<=m;
}

signed main(){
	n=read();m=read();
	int maxn=-1,minn=0x3f3f3f3f,R1=-1,R2=-1,L1=0,L2=0;
	int tot=0;
	for(int i=1;i<=n;i++){
		num[i]=read();
		tot+=num[i];
		R1=max(R1,tot);R2=R1;
	}
	R1=R2=1e14;;
	while(L1<=R1){
		int mid=(L1+R1)>>1;
		//cout<>1;
		if(check2(mid))minn=mid,R2=mid-1;
		else L2=mid+1;
	}
	//if(minn==0x3f3f3f3f)return puts("-1"),0;
	if(maxn

1.2 贪心

https://www.luogu.com.cn/problem/P4107

#include
#include
#include
#include
#include
#include
#include
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define int long long
const int N=2e6+10;
int n,m,cnt,head[N],tmp[N],ans,val[N];
struct node{
	int to,next;
}a[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline int cmp(int x,int y){
    return x

2. 计算几何

2.1 半平面交

如果不知道输入顺序,那么就顺时针逆时针都跑一遍求最大值

#include
#include
#include
#include
#include
using namespace std;

const int N=1e5+10;
const double eps=1e-13;//!
int L,R;

struct node{
	double x,y;
	inline node operator +(const node &b)const{
		return (node){x+b.x,y+b.y};
	}
	inline node operator -(const node &b)const{
		return (node){x-b.x,y-b.y};
	}
}stain[N],Cross[N];
inline node operator *(node a,double k){
	return (node){a.x*k,a.y*k};
}
inline node operator /(node a,double k){
	return (node){a.x/k,a.y/k};
}
inline double cross(node x,node y){
	return x.x*y.y-x.y*y.x;
}
inline double dot(node x,node y){
	return x.x*y.x+x.y*y.y;
}

struct nodei{
	node pos,vec;
	double angle;
	inline void add(node a,node b){//
		pos=a;vec=b;
		angle=atan2(b.y,b.x);
	}
	bool operator <(const nodei &b){
		return  angle>t;
	//while(t--){
		int n;cin>>n;
		for(int i=n;i>=1;i--)cin>>stain[i].x>>stain[i].y;
		for(int i=1;i

3. 图论

3.1 找规律

https://www.luogu.com.cn/problem/P2407

#include
#include
#include
#include
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const int N=810;
int n,m,C[N][N],R[N][N];
char a[N][N];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%s",a[i]+1);
		int aim=0;
		for(int j=1;j<=m;j++){
			if(a[i][j]=='T')aim^=1;
			R[i][j]=aim;
		}
	}
	for(int j=1;j<=m;j++){
		int aim=0;
		for(int i=1;i<=n;i++){
			if(a[i][j]=='T')aim^=1;
			C[i][j]=aim;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)putchar('o'),putchar(R[i][j]?45:32);
		cout<

3.2 最短路

https://www.luogu.com.cn/problem/P4162

SLF优化SPFA

#include
#include
#include
#include
#include
#include
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const int N=35;
const int M=910;
const int inf=0x3f3f3f3f;
int n,m,T,cnt,head[M],start[M],vis[M],cnti[M],dis[M];
double ans,DIS[M][M];
char mapi[N][N];
struct node{
	int to,next,val;
}a[M*8];

inline void add(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	a[cnt].val=w;
	head[u]=cnt;
}
inline int id(int x,int y){
	return (x-1)*m+y;
}
inline void spfa(int s){
	dequeq;
	for(int i=1;i<=n*m;i++)dis[i]=inf,vis[i]=0;
	if(start[s])dis[s]=1;else dis[s]=0;
	vis[s]=1;
	q.push_back(s);
	while(!q.empty()){
		int x=q.front();q.pop_front();
		if(dis[x]<=T)ans=max(ans,DIS[s][x]);
		vis[x]=0;
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(dis[v]>dis[x]+a[i].val){
				dis[v]=dis[x]+a[i].val;
				if(!vis[v]){
					vis[v]=1;
					if(dis[v]>n>>m>>T;
	for(int i=1;i<=n;i++){
		scanf("%s",mapi[i]+1);
		for(int j=1;j<=m;j++){
			int x=id(i,j);
			if(mapi[i][j]=='1')start[x]=1; 
		}
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	for(int k=1;k<=n;k++)for(int l=1;l<=m;l++){
		int id1=id(i,j),id2=id(k,l);
		DIS[id1][id2]=DIS[id2][id1]=(double)sqrt((double)(i-k)*(i-k)+double(j-l)*(j-l));
	}
	/*cout<<"DIS "<

3.3 Tarjan

https://www.luogu.com.cn/problem/P2469

60pts:

#include
#include
#include
#include
#include
#include
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const int N=4e4+10;
const int M=2e5+10;
const int K=6e4+10;
int n,m,cnt,head[N],cnti,headi[N],ans;
int ind,dfn[N],low[N],belong[N],vis[N];
int dfsx,true_id[N],id_true[N],dep[N],top[N],son[N],sizei[N],fa[N];
int val[N<<4],lazy[N<<4];
struct Query{
	int op,u,v,ans;
}queryi[K];
struct node{
	int to,next,flag;
}a[M],ai[M];
stacks;

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline void addi(int u,int v){
	++cnti;
	ai[cnti].to=v;
	ai[cnti].next=headi[u];
	headi[u]=cnti;
}
inline void Tarjan(int x,int fai){
	dfn[x]=low[x]=++ind;
	s.push(x);
	for(int i=head[x];i;i=a[i].next){
		if(a[i].flag==1)continue;
		int v=a[i].to;
		if(!dfn[v])Tarjan(v,x),low[x]=min(low[x],low[v]);
		else if(dfn[v]>1; 
	build(ls,l,mid);
	build(rs,mid+1,r);
	val[x]=val[ls]+val[rs];
}
inline void pushdown(int x){
	if(!lazy[x])return ;
	lazy[ls]=lazy[rs]=lazy[x];
	val[ls]=val[rs]=0;
	lazy[x]=0;
}
inline void change(int x,int l,int r,int L,int R){
	if(L>r||R=L&&r<=R)return (void)(val[x]=0,lazy[x]=1);
	pushdown(x);
	int mid=(l+r)>>1;
	if(L<=mid)change(ls,l,mid,L,R);
	if(R>mid)change(rs,mid+1,r,L,R);
	val[x]=val[ls]+val[rs];
}
inline int query(int x,int l,int r,int L,int R){
	if(L>r||R=L&&r<=R)return val[x];
	pushdown(x);
	int mid=(l+r)>>1;
	int ans=0;
	if(L<=mid)ans+=query(ls,l,mid,L,R);
	if(R>mid)ans+=query(rs,mid+1,r,L,R);
	val[x]=val[ls]+val[rs];
	return ans;
}
inline void dfs1(int x,int fai){
	sizei[x]=1;fa[x]=fai;dep[x]=dep[fai]+1;
	for(int i=headi[x];i;i=ai[i].next){
		int v=ai[i].to;
		if(v==fai)continue;
		dfs1(v,x);
		sizei[x]+=sizei[v];
		if(sizei[v]>sizei[son[x]])son[x]=v;
	}
} 
inline void dfs2(int x,int topi){
	top[x]=topi;
	true_id[x]=++dfsx;id_true[dfsx]=x;
	if(son[x]&&!true_id[son[x]])dfs2(son[x],topi);
	for(int i=headi[x];i;i=ai[i].next){
		int v=ai[i].to;
		if(true_id[v])continue;
		if(v==fa[x]||v==son[x])continue;
		dfs2(v,v);
	}
}
inline void changeline(int x,int y,int flag){
	//cout<dep[y])swap(x,y);
	if(flag)ans+=query(1,1,dfsx,true_id[x]+1,true_id[y]);
	else change(1,1,dfsx,true_id[x]+1,true_id[y]);
	//cout<=1;i--){
		ans=0;
		int ui=belong[queryi[i].u],vi=belong[queryi[i].v];
		//cout<

别人100pts:

#include
#include
#include
#include
using namespace std;
templateinline const void read(type &in)
{
    in=0;char ch=getchar();short fh=1;
    while (ch<48||ch>57)fh=ch=='-'?-1:fh,ch=getchar();
    while (ch>47&&ch<58)in=(in<<3)+(in<<1)+ch-48,ch=getchar();
    in*=fh;
}
const int N=3e4+10,M=1e5+10,Q=4e4+10;
int n,m,a[M],b[M];
stackans;
map,int>e;
struct question{int u,v,type;}q[Q]; //存储每个询问信息
class Edge
{
    private:
        int cnt;
    public:
        int head[N],to[M<<1],next[M<<1];
        inline const void addedge(int u,int v)
        {
            next[++cnt]=head[u];
            head[u]=cnt;
            to[cnt]=v;
        }
        inline const void connect(int u,int v)
        {
            addedge(u,v);
            addedge(v,u);
        }
}g,t;
class Double_Connected_Component //边双处理
{
    private:
        stacks;
        int dfn[N],low[N],cnt;
    public:
    	int dcc[N],tot;
    protected:
        inline const void tarjan(int u,int fa)
        {
            dfn[u]=low[u]=++cnt;s.push(u);int v;
            for (int i=g.head[u];i;i=g.next[i])
                if ((v=g.to[i])!=fa)
                    if (!dfn[v])tarjan(v,u),low[u]=min(low[u],low[v]);
                    else if (!dcc[v])low[u]=min(low[u],dfn[v]);
            if (low[u]!=dfn[u])return;tot++;
            do v=s.top(),s.pop(),dcc[v]=tot;while (u!=v);
        }
    public:
        inline const void tarjan()
        {
            for (int i=1;i<=n;i++)
                if (!dfn[i])
                    tarjan(i,0);
        }
        inline const void rebuild() //缩点成树
        {
            for (int i=1;i<=n;i++)
                for (int u,v,j=g.head[i];j;j=g.next[j])
                    if ((u=dcc[i])!=(v=dcc[g.to[j]]))
                        t.addedge(u,v);
        }
}dcc;
class Segment_Tree  //线段树(指针)
{
    private:
        struct tree
        {
            int sum;
            bool tag;
            tree *lson,*rson;
            inline const void pushup()
            {
                sum=lson->sum+rson->sum;
            }
            inline const void cover()
            {
                tag=1;sum=0;
            }
            inline const void pushdown()
            {
                if (!tag)return;
                lson->cover();
                rson->cover();
                tag=0;
            }
            inline const void update(int l,int r,int L,int R)
            {
                if (l>R||r=L&&r<=R)return cover();
                pushdown();
                int mid=l+r>>1;
                lson->update(l,mid,L,R);
                rson->update(mid+1,r,L,R);
                pushup();
            }
            inline const int query(int l,int r,int L,int R)
            {
                if (l>R||r=L&&r<=R)return sum;
                pushdown();
                int mid=l+r>>1;
                return lson->query(l,mid,L,R)+rson->query(mid+1,r,L,R);
            }
        }memory_pool[N<<2],*tail;
        inline const void init()
        {
            tail=memory_pool;
        }
        inline tree *spawn()
        {
            tree *p=tail++;
            p->tag=p->sum=0;
            p->lson=p->rson=NULL;
            return p;
        }
    public:
        tree *root;
        inline Segment_Tree(){init();}
        inline const void build(tree *&p,int l,int r)
        {
            p=spawn();
            if (l==r)return (void)(p->sum=(l!=1)); //边权转点权,1号点(根节点)上面没有边,权值为0
            int mid=l+r>>1;
            build(p->lson,l,mid);
            build(p->rson,mid+1,r);
            p->pushup();
        }
}sgt;
class Heavy_Light_Decomposition //树剖
{
    private:
        int size[N],top[N],fa[N],dep[N],dfn[N],wson[N],cnt;
    public:
        inline const void dfs(int p)
        {
            size[p]=1;
            for (int i=t.head[p];i;i=t.next[i])
            {
                int son=t.to[i];
                if (son==fa[p])continue;
                fa[son]=p;dep[son]=dep[p]+1;
                dfs(son);size[p]+=size[son];
                if (size[son]>size[wson[p]])wson[p]=son;
            }	
        }
        inline const void dfs(int p,int tp)
        {
            top[p]=tp;dfn[p]=++cnt;
            if (wson[p])dfs(wson[p],tp);
            for (int son,i=t.head[p];i;i=t.next[i])
                if (!dfn[son=t.to[i]])
                    dfs(son,son);
        }
        inline const void update(int a,int b)
        {
            while (top[a]^top[b])
            {
                if (dep[top[a]]update(1,dcc.tot,dfn[top[a]],dfn[a]);
                a=fa[top[a]];
            }
            if (dep[a]>dep[b])swap(a,b);
            sgt.root->update(1,dcc.tot,dfn[a]+1,dfn[b]);
        }
        inline const int query(int a,int b)
        {
            int ans=0;
            while (top[a]^top[b])
            {
                if (dep[top[a]]query(1,dcc.tot,dfn[top[a]],dfn[a]);
                a=fa[top[a]];
            }
            if (dep[a]>dep[b])swap(a,b);
            return ans+sgt.root->query(1,dcc.tot,dfn[a]+1,dfn[b]);
        }
}hld;
int main()
{
    read(n);read(m);
    for (int i=1;i<=m;i++)read(a[i]),read(b[i]);
    int qtot;
    for (qtot=1;read(q[qtot].type),~q[qtot].type;qtot++)
    {
        read(q[qtot].u);read(q[qtot].v);
        if (q[qtot].type)continue;
        e[make_pair(q[qtot].u,q[qtot].v)]++;
		e[make_pair(q[qtot].v,q[qtot].u)]++; //无向图,反过来的也要更改
	}
    for (int i=1;i<=m;i++)
        if (e.find(make_pair(a[i],b[i]))!=e.end()&&e[make_pair(a[i],b[i])])
			e[make_pair(a[i],b[i])]--,e[make_pair(b[i],a[i])]--;
		else g.connect(a[i],b[i]);
    dcc.tarjan();dcc.rebuild();
    hld.dfs(1);hld.dfs(1,1);
    sgt.build(sgt.root,1,dcc.tot);
    for (int i=qtot-1;i;i--)
        if (q[i].type)ans.push(hld.query(dcc.dcc[q[i].u],dcc.dcc[q[i].v])); //由于是倒序处理,所以输出也要倒过来,因为tarjan缩点的时候会用到栈,干脆也用栈来实现倒序好了
        else hld.update(dcc.dcc[q[i].u],dcc.dcc[q[i].v]);
    while (ans.size())printf("%d\n",ans.top()),ans.pop();
    return 0;
}

3.4 网络流

3.4.1 费用流

https://www.luogu.com.cn/problem/P2469

#include
#include
#include
#include
#include
#include
#include
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const int N=160010;
const int inf=0x3f3f3f3f;
int n,m,start,endi,cnt=1,head[N];
int maxnflow,maxncost,vis[N],flow[N],pre[N],dis[N];
struct node{
	int to,next,val,cost;
}a[N*3];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void addi(int u,int v,int w,int x){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].cost=x;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline void add(int u,int v,int w,int x){
	addi(u,v,w,x);addi(v,u,0,-x);
}
inline int spfa(int s,int t){
	memset(dis,inf,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queueq;
	dis[s]=0;flow[s]=inf;vis[s]=1;
	q.push(s);
	while(!q.empty()){
		int x=q.front();q.pop();
		vis[x]=0;
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(dis[v]>dis[x]+a[i].cost&&a[i].val){
				dis[v]=dis[x]+a[i].cost;
				flow[v]=min(flow[x],a[i].val);
				pre[v]=i;
				if(!vis[x])vis[v]=1,q.push(v);
			}
		}
	}
	return dis[t]!=inf;
}
inline void update(int s,int t){
	int x=t;
	while(x!=s){
		int xi=pre[x];
		a[xi].val-=flow[t];
		a[xi^1].val+=flow[t];
		x=a[xi^1].to;
	}
	maxnflow+=flow[t];
	maxncost+=flow[t]*dis[t];
}
inline void EK(int s,int t){
	while(spfa(s,t))update(s,t);
}

int main(){
	n=read();m=read();
	start=n*2+1,endi=n*2+2;
	for(int i=1;i<=n;i++){
		int x=read();
		add(start,i,1,0);
		add(start,i+n,1,x);
		add(i+n,endi,1,0);
	}
	for(int i=1;i<=m;i++){
		int u,v,w;
		u=read();v=read();w=read();
		if(u>v)swap(u,v);
		add(u,v+n,1,w);
	}
	EK(start,endi);
	cout<

4. 数学

4.1 矩阵加速

https://www.luogu.com.cn/problem/P2461

呵呵,输出必须是非负整数!!

20pts:

#include
#include
#include
#include
#include
#include
#include
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define int long long
const int N=20;
int n,m,K,mod;
struct Matrix{
	int num[N][N];
	Matrix(){
		memset(num,0,sizeof(num));
	}
	inline Matrix operator *(const Matrix &b)const{
		Matrix c;
		for(int i=1;i<=K;i++)
		for(int j=1;j<=K;j++)
		for(int k=1;k<=K;k++)
		c.num[i][j]=(c.num[i][j]+num[i][k]*b.num[k][j]%mod)%mod;
		return c;
	}
}ans,basic;

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline Matrix operator ^(Matrix x,int y){
	Matrix fin=x;--y;
	while(y){
		if(y&1)fin=fin*x;
		x=x*x;
		y>>=1;
	}
	return fin;
}

signed main(){
	K=read();
	for(int i=1;i<=K;i++)ans.num[i][1]=read();
	for(int i=K;i>=1;i--){
		if(i0)ans=(basic^(m-K))*ans;
	//cout<<"ans "<

100pts:

#include
#include
#include
#include
#include
#include
#include
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

#define int long long
const int N=20;
int n,m,K,mod,sum[N];
struct Matrix{
	int num[N][N];
	Matrix(){
		memset(num,0,sizeof(num));
	}
	inline Matrix operator *(const Matrix &b)const{
		Matrix c;
		for(int i=1;i<=K+1;i++)
		for(int j=1;j<=K+1;j++)
		for(int k=1;k<=K+1;k++)
		c.num[i][j]=(c.num[i][j]+num[i][k]*b.num[k][j]%mod)%mod;
		return c;
	}
}ans,basic;

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline Matrix operator ^(Matrix x,int y){
    Matrix fin;
    if(y==0)return fin;
	fin=x;--y;
	while(y>0){
		if(y&1)fin=fin*x;
		x=x*x;
		y>>=1;
	}
	return fin;
}

signed main(){
	K=read();
	for(int i=1;i<=K;i++)ans.num[i][1]=read();
	for(int i=K;i>=1;i--){
		if(i

5. 动态规划

5.1 贪心优化

https://www.luogu.com.cn/problem/P2577

这个看似可以记忆化搜索。

#include
#include
#include
#include
#include
#include
#include
#define ls (x)<<1
#define rs (x)<<1|1
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const int N=210;
const int inf=0x3f3f3f3f;
int n,f[N][N*N],sum[N];
struct node{
	int wait,eat;
	bool operator <(const node &b)const{
		return eat>b.eat;
	}
}a[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}

int main(){
	n=read();
	for(int i=1;i<=n;i++)a[i].wait=read(),a[i].eat=read();
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i].wait;
	memset(f,inf,sizeof(f));
	f[0][0]=0;
	for(int i=1;i<=n;i++)
	for(int j=0;j<=sum[i];j++){
		if(j>=a[i].wait)f[i][j]=min(f[i][j],max(f[i-1][j-a[i].wait],j+a[i].eat));
		f[i][j]=min(f[i][j],max(f[i-1][j],sum[i]-j+a[i].eat));
	}
	int ans=inf;
	for(int i=0;i<=sum[n];i++)ans=min(ans,f[n][i]);
	cout<