一道题开一篇文章实在浪费,于是决定以后零零散散做的题就放在这个集子里了。如果数量过多会考虑再开。

JSOI2004 平衡点(模拟退火)

提交入口

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

题目描述

如图,有 $n$ 个重物,每个重物系在一条足够长的绳子上。

每条绳子自上而下穿过桌面上的洞,然后系在一起。图中 $x$ 处就是公共的绳结。假设绳子是完全弹性的(即不会造成能量损失),桌子足够高(重物不会垂到地上),且忽略所有的摩擦,求绳结 $x$ 最终平衡于何处。

注意:桌面上的洞都比绳结 $x$ 小得多,所以即使某个重物特别重,绳结 $x$ 也不可能穿过桌面上的洞掉下来,最多是卡在某个洞口处。

47-1
47-1

输入格式

文件的第一行为一个正整数 $n$$1\le n\le 1000$),表示重物和洞的数目。

接下来的 $n$ 行,每行是 $3$ 个整数 $x_i, y_i, w_i$,分别表示第 $i$ 个洞的坐标以及第 $i$ 个重物的重量。($-10000\le x_i,y_i\le10000, 0<w_i\le1000$

输出格式

你的程序必须输出两个浮点数(保留小数点后三位),分别表示处于最终平衡状态时绳结 $x$ 的横坐标和纵坐标。两个数以一个空格隔开。

样例输入 #1

3
0 0 1
0 2 1
1 1 1

样例输出 #1

0.577 1.000

分析

待续。先贴代码。

#include <bits/stdc++.h>
using namespace std;

const int MAXN =1e4+10;
int n,g[MAXN];
double minlen=DBL_MAX;

struct Point{
	double x, y;
	Point(double a=0.0, double b=0.0):x(a),y(b){}
}P[MAXN];
Point ans;

inline double Sqr(double x){return x*x;}

inline double Rand(){
	return double(rand())/double(RAND_MAX);
}

inline double dis(Point a,Point b){
	return sqrt(Sqr(a.x-b.x)+Sqr(a.y-b.y));
}

bool accept(double delta,double temp){
	return delta<0||Rand()<exp(-delta/temp);
}

double calc(Point origin){
	double len=0;
	for(int i=0;i<n;i++)
	    len+=dis(origin,P[i])*g[i];
	if(len<minlen){
		ans=origin;
		minlen=len;
	}
	return len;
}

void SA(Point ans0,double T0,double dec,double end){
	double temp=T0;
	Point nowpos=ans0;
	double nowlen=calc(nowpos);
	
    while(temp>end){
		Point nextpos=Point(nowpos.x+temp*(Rand()*2-1),nowpos.y+temp*(Rand()*2-1));
		double nlen=calc(nextpos);
		if(accept(nlen-nowlen,temp)){
			nowpos=nextpos;
			nowlen=nlen;
		}
		temp*=dec;   //dec为退火系数 
	}
	
    for(int i=0;i<1000;i++){ //精度维护
		Point rnd=Point(ans.x+temp*(Rand()*2-1),ans.y+temp*(Rand()*2-1));
		calc(rnd);
	}
}

int main(){
	scanf("%d",&n);
	Point init;
	for(int i=0;i<n;i++){
		scanf("%lf%lf%d",&P[i].x,&P[i].y,&g[i]);
		init.x+=P[i].x;
		init.y+=P[i].y;
	}
	init.x/=n;
	init.y/=n;
	SA(init,1e5,1-1e-2,1e-3);
	
	printf("%.3f %.3f\n",ans.x,ans.y);
	return 0;
}

有机化学之神偶尔会做作弊(tarjan, lca)

提交入口

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

题意简述

给你一个 $n$ 个点,$m$ 条边的无向图。把图中所有的环变为一个点,求变化后某两个点之间有多少个点。

输入格式

第一行两个整数 $n$$m$。表示有 $n$ 个点,$m$ 根键。

接下来 $m$ 行每行两个整数 $u$$v$ 表示 $u$ 号碳和 $v$ 号碳有一根键。

接下来一个整数 $tot$ 表示询问次数。

接下来 $tot$ 行每行两个整数,$a$$b$ 表示询问的两个碳的编号。

输出格式

$tot$ 行,每行一个二进制数,表示答案。

样例输入 #1

3 2
1 2
2 3
2
1 2
2 3

样例输出 #1

10
10

提示

两个碳不成环。

数据范围及约定

对于 $100\%$ 的数据,$1<n\le10 ^ 4$$1<m\le5\times 10 ^ 4$

代码

#include <cstdio>
#include <cmath>
#include <algorithm>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
using namespace std;

const int maxn=1e4+3;
const int maxm=1e5+3;
// Edge_number in a general graph is twice that of a one-way graph
struct Edge{int v,next;};
Edge edge[maxm],edge2[maxm];
int head[maxn],dfn[maxn],low[maxn],stac[maxn],color[maxn],fa[maxn];
int n,m,tot,num,top,cnt,tot_in_txt,lcafa[maxn][25];
int head2[maxn],tot2,dep[maxn],max0;
bool ins[maxn], vis[maxn];

const int topow[] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192};

inline void rd(int &x){
    int w=x=0;
    char ch=0;
    while(ch<'0'||'9'<ch) w|=(ch=='-'),ch=getchar();
    while('0'<=ch&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
    x=w?-x:x;
}

inline void addedge(int x,int y){
    edge[++tot].v=y;
    edge[tot].next=head[x];
    head[x]=tot;
}

inline void addedge2(int x,int y){
    edge2[++tot2].v=y;
    edge2[tot2].next=head2[x];
    head2[x]=tot2;
}

void tarjan(int x){
    low[x]=dfn[x]=++num;
    stac[++top]=x; ins[x]=true;
    for(int i=head[x];i;i=edge[i].next){
        int y=edge[i].v;
        if(!dfn[y]){
            fa[y]=x;
            tarjan(y);
            low[x]=MIN(low[x],low[y]);
        }
        else if(ins[y] && y!=fa[x]){
            low[x]=MIN(low[x],dfn[y]);
        }
    }
    if(dfn[x]==low[x]){
        ++cnt; int y;
        do{
            y=stac[top--]; ins[y]=false;
            color[y]=cnt;
        }while(x!=y);
    }
}

void lcainit(int x){
    vis[x] = true;
    for(int i=1;i<=max0;i++)
        if(lcafa[x][i-1])lcafa[x][i]=lcafa[lcafa[x][i-1]][i-1];
        else break;

    for(int i=head2[x];i;i=edge2[i].next){
        int y=edge2[i].v;
        if(y!=lcafa[x][0]){
            lcafa[y][0]=x;
            dep[y]=dep[x]+1;
            if(!vis[y]) lcainit(y);
        }
    }
}

inline int lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int delta=dep[u]-dep[v];
    for(int x=0;x<=max0;x++)
        if((1<<x)&delta)u=lcafa[u][x];
    if(u==v)return u;
    for(int x=max0;x>=0;x--)
        if(lcafa[u][x]!=lcafa[v][x]){
            u=lcafa[u][x];
            v=lcafa[v][x];
        }
    return lcafa[u][0];
}

int main(){
    rd(n); rd(m);
    for(int i=1;i<=m;i++){
        int x,y;
        rd(x); rd(y);
        addedge(x,y);
        addedge(y,x);
    }
    rd(tot_in_txt);

    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i);
    }

    for(int x=1;x<=n;x++){
        for(int i=head[x];i;i=edge[i].next){
            int y=edge[i].v;
            if(color[x]!=color[y]){
                addedge2(color[x], color[y]);
                addedge2(color[y], color[x]);
            }
        }
    }

    max0=(int)(log(cnt)/log(2))+3;
    lcainit(1);

    while(tot_in_txt--){
        int a,b;
        rd(a); rd(b);
        int k = lca(color[a], color[b]);
        int temp = dep[color[a]] + dep[color[b]] - (dep[k]<<1) + 1;

        char ans[15] = "00000000000000";
        for(int i=13; ~i; i--){
            if(temp>=topow[i]){
                ans[13-i] = '1';
                temp -= topow[i];
            }
        }
        int i = 0;
        while(ans[i]=='0') i++;
        for(; i<=13; i++)putchar(ans[i]);
        putchar('\n');
    }

    return 0;
}

yLOI2022 枕万梦(排序)

提交入口

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

题目描述

天亮了,扶苏不敌困意,早早地进入了梦乡。在失去引力的梦里,扶苏遇到了好多串漂浮着的数列,它们的长度都相等,而且都是美妙的等比数列!出于本能,扶苏想要把这些数列按照字典序排序,可是在梦里扶苏失去了思考的能力,请你来帮帮她!

具体地,有 $n$ 个编号从 $1$$n$ 的数列 $a_1, a_2, \dots a_n$,每个数列的长度均为 $m + 1$。第 $i$ 个数列 $a_i$ 满足递推式 $a_{i,j} = a_{i,j - 1} \times i$,其中 $1 \leq j \leq m$。而扶苏会告诉你每个序列的首项 $a_{i,0}$,你需要帮助她把这些数列按字典序排序。

输入格式

输入的第一行是两个整数,依次表示 $n$$m$
接下来 $n$ 行,每行一个整数,第 $i$ 行的整数表示数列 $a_i$ 的首项 $a_{i,0}$

输出格式

输出一行 $n$ 个整数,第 $i$ 个整数表示字典序第 $i$ 小的数列的编号

样例 #1

样例输入 #1

2 2
1
2

样例输出 #1

1 2

样例 #2

样例输入 #2

2 3
1
-1

样例输出 #2

2 1

样例 #3

样例输入 #3

2 2
1
1

样例输出 #3

1 2

样例 #4

样例输入 #4

见附加文件中的 B4.in

样例输出 #4

见附加文件中的 B4.ans

提示

样例 1 解释

共有两个数列,每个数列的长度均为 $2+1=3$

对第一个数列 $a_1$

  • 已知其首项 $a_{1,0} = 1$
  • 根据 $a_{i,j} = a_{i,j - 1} \times i$,取 $i=1,j = 1$ 可以得到 $a_{1,1} = a_{1,0} \times 1 = 1$
  • 根据 $a_{i,j} = a_{i,j - 1} \times i$,取 $i=1,j = 2$ 可以得到 $a_{1,2} = a_{1,1} \times 1= 1$

所以数列 $a_1$$1,1,1$

对第二个数列 $a_2$

  • 已知其首项 $a_{2,0} = 2$
  • 根据 $a_{i,j} = a_{i,j - 1} \times i$,取 $i=2,j = 1$ 可以得到 $a_{2,1} = a_{2,0} \times 2 = 2 \times 2 = 4$
  • 根据 $a_{i,j} = a_{i,j - 1} \times i$,取 $i=2,j = 2$ 可以得到 $a_{2,2} = a_{2,1} \times 2= 4 \times 2 = 8$

所以数列 $a_2$$2,4,8$

比较字典序可得数列 $a_1$ 是字典序最小的数列。所以输出 $1$

样例 2 解释

数列 $a_1$$1,1,1,1$,数列 $a_2$$-1, -2,-4,-8$

数据规模与约定 本题共 $10$ 个测试点,各测试点信息如下表:

47-2
47-2

特殊约定 A:保证 $a_{i,0}$ 均相等。
特殊约定 B:保证 $a_{i,0}$ 互不相等。

对全部的测试点,保证 $1 \leq n \leq 10^5$$1 \leq m \leq 10^9$$1 \leq |a_{i,0}| \leq 10^9$

提示

对两个数列 $a_i, a_j$,按如下方式比较其字典序:

找到最小的满足 $a_{i,p} \neq a_{j, p}$ 的下标 $p$,比较 $a_{i, p}$$a_{j, p}$ 的大小:

  • 如果 $a_{i,p} < a_{j, p}$,则称 $a_i$ 的字典序比 $a_j$ 的小。
  • 如果 $a_{i,p} > a_{j, p}$,则称 $a_i$ 的字典序比 $a_j$ 的大。

可以证明,在本题的限制下,这样的 $p$ 一定存在。

分析

要求根据字典序排序。若两个数列第一个元素就不等,便可比较大小;若两个数列第一个元素相等,由数列定义,第二个元素必然不等,于是可比较大小。对于首元素为零的数列,整个数列都是零。由此得到下述做法:

对于两个不等的 $a_{i,0}$ , 升序排序。对于两个相等的 $a_{i,0}$ , 分正负两种情况:若 $a_{i,0}>0$ , 则行数越大,位序靠后;若 $a_{i,0}<0$ , 则行数越大,位序靠前。

#include <algorithm>
#include <cstdio>
using LL = long long;
using namespace std;

LL n,m;

struct mnode{
    LL mcontent;
    LL mindex;
    bool operator < (const mnode& v)const{
        if(mcontent != v.mcontent)
            return mcontent < v.mcontent;
        else    
            if(mcontent > 0)
                return mindex < v.mindex;
            else 
                return mindex > v.mindex;
    }
}marray[100010];

int main(){
    scanf("%lld%lld",&n,&m);
    for(LL i=1; i<=n; i++){
        LL x; 
        scanf("%lld",&x);
        marray[i].mcontent = x;
        marray[i].mindex = i;
    }

    sort(marray+1, marray+1+n);

    for(LL i=1; i<=n; i++){
        printf("%lld ",marray[i].mindex);
    }

    return 0;
}

平衡二叉树

最近考研应试之余,尝试着用王道的思路手写了平衡二叉树的代码,但是没有完成,只是个半成品。如果之后还记得的话,也许我会完成它?

#include <cstdio>
#define MAX(a,b) ((a)>(b)?(a):(b))

inline void rd(int &x){
    int w=x=0;
    char ch=0;
    while(ch<'0'||'9'<ch) w|=(ch=='-'),ch=getchar();
    while('0'<=ch&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
    x=w?-x:x;
}

struct avlNode{
    int value;
    int cnt;
    int lsub_h;   //left sub_tree's height
    int rsub_h;
    int lsub_num; //size of leftSubtree, excluding itself
    int rsub_num;
    avlNode *lchild, *rchild, *fa;
};

class avlTree{
public:
    avlTree(){ T = nullptr; }

    avlNode* getRoot(){ return T; }
    
    void insertX(avlNode*& K, int x){
        avlNode* p = bstInsert(K, x, nullptr);
        maintain_balance_insert(p);
    }

    void deleteX(int x){  // assume there is x
        avlNode* p = find_X_delete(T, x);
        p->cnt--;
        if(p->cnt>=1)return;

        if(p->lchild==nullptr&&p->rchild==nullptr){
            if(p==p->fa->lchild)
                p->fa->lchild = nullptr;
            else 
                p->fa->rchild = nullptr;
        }

        else if(p->lchild!=nullptr&&p->rchild==nullptr){ // !
            if(p==p->fa->lchild)
                p->fa->lchild = p->lchild;
            else
                p->fa->rchild = p->lchild;
            p->lchild->fa = p->fa;
        }

        else if(p->lchild==nullptr&&p->rchild!=nullptr){
            if(p==p->fa->lchild)
                p->fa->lchild = p->rchild;
            else
                p->fa->rchild = p->rchild;
            p->rchild->fa = p->fa;
        }

        else {
            avlNode* qwq = maxValue_in_lsubtree(p);
            p->value = qwq->value;
            p->cnt = qwq->cnt;
            p = qwq;
            if(p==p->fa->lchild)
                p->fa->lchild = p->lchild;
            else
                p->fa->rchild = p->lchild;
            p->lchild->fa = p->fa;
        }
        
        maintain_balance_delete(p);
        delete p;
    }
    
    int index_X(int x){
        //find an avlNode whose value is x,return its index
        //at this point, the binary-tree is balanced
        avlNode* p = find_X(T, x);   // O(logN)
        int ans = -1;
        if(p==p->fa->rchild){
            avlNode* G = find_left_daddy(p);
            ans = G->lsub_num + G->rsub_num + G->cnt
                  - p->rsub_num - p->cnt + 1;
                  //+1: the value-x avlNode goes the end
        }
        else if(p==p->fa->lchild){
            avlNode* G = find_right_daddy(p);
            ans = G->fa->lsub_num + G->fa->cnt
                  + p->lsub_num + 1;
        }
        if(ans==-1) printf("No such avlNode.\n");
        return ans;
    }
    
    int findIndex_X(){
        //Query the avlNode whose index is x, return its value
    }
    
    int preX(){}
    
    int afterX(){}

private:
    avlNode* find_X(avlNode* K, int x){
        while(K!=nullptr && x!=K->value){
            if(x<K->value) K=K->lchild;
            else K=K->rchild;
        }
        if(K==nullptr)
            printf("function find_X() failed.\n");
        return K;
    }

    avlNode* find_X_delete(avlNode* K, int x){
        while(K!=nullptr && x!=K->value){
            if(x<K->value){
                K->lsub_num--;
                K=K->lchild;
            }
            else {
                K->rsub_num--;
                K=K->rchild;
            }
        }
        if(K==nullptr)
            printf("function find_X() failed.\n");
        return K;
    }

    avlNode* find_left_daddy(avlNode* p){}

    avlNode* find_right_daddy(avlNode* p){}

    int lsubtree_height(avlNode* x){
        if(x->lsub_h) return x->lsub_h;
        if(x->lchild==nullptr){
            x->lsub_h = 0;
            return x->lsub_h;
        }
        x->lsub_h = MAX(lsubtree_height(x->lchild), 
                        rsubtree_height(x->lchild))+ 1;
        return x->lsub_h;
    }

    int rsubtree_height(avlNode* x){
        if(x->rsub_h) return x->rsub_h;
        if(x->rchild==nullptr){
            x->rsub_h = 0;
            return x->rsub_h;
        }
        x->rsub_h = MAX(lsubtree_height(x->rchild), 
                        rsubtree_height(x->rchild))+ 1;
        return x->rsub_h;
    }

    avlNode* find_Unbalanced_Node(avlNode* p){
        int sub_balance = 0;
        while(sub_balance>=-1&&sub_balance<=1){ //sub_balance = 0,1,-1
            p = p->fa;
            if(p==nullptr) return p;
            p->lsub_h = p->rsub_h = 0; // erase old data
            int lch = lsubtree_height(p);
            int rch = rsubtree_height(p);
            sub_balance = lch-rch;
        }
        return p;
    }

    avlNode* bstInsert(avlNode* K, int x, avlNode* myfa){
        if(K==nullptr){
            K = new avlNode;
            K->value = x;
            K->fa = myfa;
            K->lchild = K->rchild = nullptr;
            return K;
        }
        else if(x==K->value){
            K->cnt++;
            return K;
        }
        else if(x < K->value){
            K->lsub_num++;     // nice code <(ˉ^ˉ)>
            bstInsert(K->lchild, x, K);
        }
        else{
            K->rsub_num++;
            bstInsert(K->rchild, x, K);
        }
    }

    void maintain_balance_insert(avlNode* p){
        avlNode* subroot = find_Unbalanced_Node(p);
        // after find_Unbalanced_Node, lsub_h & rsub_h is updated
        if(subroot->lchild->lsub_h==subroot->lchild->rsub_h+1){
            rightRotation(subroot->lchild);
        }
        else if(subroot->rchild->lsub_h+1==subroot->rchild->rsub_h){
            leftRotation(subroot->rchild);
        }
        else if(subroot->lchild->lsub_h+1==subroot->lchild->rsub_h){
            leftRotation(subroot->lchild->rchild);
            rightRotation(subroot->lchild);
        }
        else if(subroot->rchild->lsub_h==subroot->rchild->rsub_h+1){
            rightRotation(subroot->rchild->lchild);
            leftRotation(subroot->rchild);
        }
    }

    void maintain_balance_delete(avlNode* p){
        // 删除的节点向上计算 balance
        avlNode* subroot = find_Unbalanced_Node(p);
        if(subroot==nullptr) return;
        // to do 
    }

    void leftRotation(avlNode* p){
        avlNode *f = p->fa, *gf = f->fa;
        f->rchild = p->lchild;
        f->rsub_num = p-> lsub_num;
        f->rchild->fa = f;
        p->lchild = f;
        p->lsub_num = f->lsub_num + f->rsub_num + 1;
        f->fa = p;
        if(gf->lchild==f){
            gf->lchild = p;
        }
        else if(gf->rchild==f){
            gf->rchild = p;
        }
        p->fa = gf;
    }

    void rightRotation(avlNode* p){
        avlNode *f = p->fa, *gf = f->fa;
        f->lchild = p->rchild;
        f->lsub_num = p-> rsub_num;
        f->lchild->fa = f;
        p->rchild = f;
        p->rsub_num = f->lsub_num + f->rsub_num + 1;
        f->fa = p;
        if(gf->lchild==f){
            gf->lchild = p;
        }
        else if(gf->rchild==f){
            gf->rchild = p;
        }
        p->fa = gf;
    }

    avlNode* maxValue_in_lsubtree(avlNode* p){}

    avlNode* T;  // root
};

avlTree P3369;
int main(){
    int n; rd(n);
    avlNode* rooT = P3369.getRoot();
    while(n--){
        int opt, x;
        rd(opt); rd(x);
        switch(opt){
            case 1: P3369.insertX(rooT, x); break;
            case 2: P3369.deleteX(x); break;
            case 3: printf("%d\n", P3369.index_X(x)); break;
            case 4: printf("%d\n", P3369.findIndex_X()); break;
            case 5: printf("%d\n", P3369.preX()); break;
            case 6: printf("%d\n", P3369.afterX()); break;
        }
    }
    return 0;
}

5 倍经验日(背包)

题目背景

现在乐斗有活动了!每打一个人可以获得 5 倍经验!absi2011 却无奈的看着那一些比他等级高的好友,想着能否把他们干掉。干掉能拿不少经验的。

题目描述

现在 absi2011 拿出了 $x$ 个迷你装药物(嗑药打人可耻…),准备开始与那些人打了。

由于迷你装药物每个只能用一次,所以 absi2011 要谨慎的使用这些药。悲剧的是,用药量没达到最少打败该人所需的属性药药量,则打这个人必输。例如他用 $2$ 个药去打别人,别人却表明 $3$ 个药才能打过,那么相当于你输了并且这两个属性药浪费了。

现在有 $n$ 个好友,给定失败时可获得的经验、胜利时可获得的经验,打败他至少需要的药量。

要求求出最大经验 $s$,输出 $5s$

输入格式

第一行两个数,$n$$x$

后面 $n$ 行每行三个数,分别表示失败时获得的经验 $\mathit{lose}_i$,胜利时获得的经验 $\mathit{win}_i$ 和打过要至少使用的药数量 $\mathit{use}_i$

输出格式

一个整数,最多获得的经验的五倍。

样例 #1

样例输入 #1

6 8
21 52 1
21 70 5
21 48 2
14 38 3
14 36 1
14 36 2

样例输出 #1

1060

提示

【Hint】

五倍经验活动的时候,absi2011 总是吃体力药水而不是这种属性药。

【数据范围】

  • 对于 $10\%$ 的数据,保证 $x=0$
  • 对于 $30\%$ 的数据,保证 $0\le n\le 10$$0\le x\le 20$
  • 对于 $60\%$ 的数据,保证 $0\le n,x\le 100$$10<lose_i,win_i\le 100$$0\le use_i\le 5$
  • 对于 $100\%$ 的数据,保证 $0\le n,x\le 10^3$$0<lose_i\le win_i\le 10^6$$0\le use_i\le 10^3$

【题目来源】

fight.pet.qq.com

absi2011 授权题目

分析

为防止学校自命题出 dp 埋伏一手,还是练两道为妙。

整体思路看起来比较显然,但是特判会有点麻烦。大佬们都是用数组的,我还是老老实实用记忆化搜索。

#include <cstdio>
#define MAX(a,b) ((a)>(b)?(a):(b))

const int MAXN = 1e3+5;
int f[MAXN][MAXN],lose[MAXN],win[MAXN],use[MAXN];

int dp(int n, int w){
    if(n<=0) return 0;
    if(f[n][w]) return f[n][w];
    if(!use[n]){
        f[n][w] = dp(n-1,w) + win[n];
        return f[n][w];
    }
    if(!w){
        f[n][w] = dp(n-1,0) + lose[n];
        return f[n][w];
    }
    int temp1 = dp(n-1,w) + lose[n];
    int temp2 = (w-use[n]>=0)?(dp(n-1,w-use[n]) + win[n]):0;
    f[n][w] = MAX(temp1, temp2);
    return f[n][w];
}

int main(){
    int n, x;
    scanf("%d%d",&n,&x);
    
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&lose[i],&win[i],&use[i]);
    }

    printf("%lld",5ll*dp(n,x));
    return 0;
}

杂记

# define MAX(a,b) ((a)>(b)?(a):(b))
# define MIN(a,b) ((a)<(b)?(a):(b))

这个常见的宏定义有大问题,今天被我遇到了。 来看导致问题的代码:

alpha = MAX(alpha, alpha_beta(T, alpha, beta, false));

在编译前,宏会把这行代码展开,它实际变成了:

alpha = ((alpha) > (alpha_beta(T, alpha, beta, false)) ? (alpha) : (alpha_beta(T, alpha, beta, false)));

这个函数调用在展开后的代码里出现了两次!

永远不要将带有副作用或计算成本高昂的表达式(如函数调用)直接放在宏参数中。

后记

不再给出代码,仅给出链接。

请参考: https://github.com/dropsong/ac_records