随笔 - 188  文章 - 0  评论 - 59  阅读 - 7707

暑期集训加餐

rank...你知道我垫底就行了。mark 20

T1:(蛋糕)区间DP;T2:(游戏)贪心+dij最短路优化坐标的转移:对性质的判断和算法优化的可行性

T1:A和B分n块排成环的蛋糕,A先从里面任意拿一块,B每次都会拿最大的,A和B轮流拿,每次只能拿旁边至少一块蛋糕已经被拿走的蛋糕,每个蛋糕有一个价值,求A可以获得的最大价值。(n<=2000)

(1)dfs+记忆化:因为A的选择决定了B的选择,所以只枚举A选择哪块蛋糕就行,2^(n/2),看起来很悬,但是你加一个dp[l][r]:表示当前正在选(l,r)区间范围的蛋糕,A是要选的那个人,每次选完记录一下dp[l][r],下次到这就不搜了。就可以过了。

特别离谱的贪心就别搞了,安心打个暴力没准能A


#define int ll
inline int Max(int a,int b){return (a>b)?(a):b;}
inline int Min(int a,int b){return (a<b)?(a):b;}
int n;
int a[6010];
int dp[7000][7000];
int cnt=0;
inline int dfs(int l,int r)
{
	//++cnt;if(cnt>100)exit(0);
	//chu("l:%d  r:%d\n",l,r);
	if(dp[l][r]!=-1)return dp[l][r];
	if(r-l+1>n){
		dp[l][r]=0;return 0;
	}
	if(r-l+1==n)//如果已经最后唯一选择
	{
		dp[l][r]=min(a[l],a[r]);return dp[l][r];
	}
	//相当于是有2种选择,我从里面选出一种最优的作为dp[l][r]的值并且返回
	//如果是A选l
	if(a[l-1]>a[r])
	{
		dp[l][r]=a[l-1]+dfs(l-2,r);
	}
	else dp[l][r]=a[r]+dfs(l-1,r+1);
	if(a[l]>a[r+1])
	{
		dp[l][r]=Min(dp[l][r],a[l]+dfs(l-1,r+1));
	}
	else dp[l][r]=Min(dp[l][r],a[r+1]+dfs(l,r+2));
	return dp[l][r];
}
signed main()
{
//	freopen("","r",stdin);
//	freopen("","w",stdout);
	
	n=re();int tot=0;
	_f(i,1,n)
	{
		a[i]=re();a[i+n]=a[i+2*n]=a[i];
		tot+=a[i];
	}//3倍链
	//dfs(int l,int r,int sum)当前准备选择的左右边界,B获得的价值,return 到结束为止的最小sum
	//记忆化?就是剪?如果sum>dp[i][j]直接return dp[i][j]
	//dp[i][j]:当前状态i,j,A正准备选择的最小价值
	_f(i,0,n*3+10)
	_f(j,0,n*3+10)
	dp[i][j]=-1;
	int ans=1e17;
	_f(i,n+1,(n<<1))
	{
		if(a[i-1]>a[i+1])ans=min(ans,dfs(i-2,i+1)+a[i-1]);
		else ans=min(ans,dfs(i-1,i+2)+a[i+1]);
	}
	chu("%lld",tot-ans);
	return 0;
}
/*
5
2 8 1 10 9

12
816 469 799 183 660 250 298 118 925 91 52 970

3743
离谱贪心:
枚举起点,贪心让酱小
好像挺对的,呵呵
*/

(2)DP:dp[i][j]代表当前选完了[l,r]区间的A的最大价值
dp[i][j]=max(dp[i][j],val[i]+dp[i+2][j]/dp[i+1][j-1])(depend on val of val[i+1],val[j])
dp[i][j]=max(dp[i][j],val[j]+dp[i][j-2]/dp[i+1][j-1])(depend on val of val[i],val[j-1])

#include <bits/stdc++.h>
#define fre(x) freopen( #x ".in", "r", stdin ), freopen( #x ".out", "w", stdout )
using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double db;
const int N = 4e3 + 10;

mt19937 mt( (ull)(&N) );
int Rand ( int l, int r ) { return uniform_int_distribution<>(l,r)(mt); }

#define int ll

int n, len, arr[N], dp[N][N];

void Solve ()
{
	cin >> n, len = 2*n;
	for( int i = 1; i <= n; ++i ) cin >> arr[i], arr[i+n] = arr[i];
	for( int i = 1; i <= len; ++i ) dp[i][i] = arr[i];
	for( int l = 2; l <= n; ++l ) for( int i = 1, j = i+l-1; j <= len; ++i, ++j )
		dp[i][j] = max( dp[i][j], arr[i] + ( arr[i+1] > arr[j] ? dp[i+2][j] : dp[i+1][j-1] ) ),
		dp[i][j] = max( dp[i][j], arr[j] + ( arr[i] > arr[j-1] ? dp[i+1][j-1] : dp[i][j-2] ) );
	int res = 0;
	for( int i = 1; i <= n; ++i ) res = max( res, dp[i][i+n-1] );
	cout << res << "\n";
}

signed main ()
{
	//fre(x);
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); Solve(); return 0;
}

T2:给你平面坐标系上的n个点,要求你从(x1,y1)出发,到(xn,yn),你有2种移动方式(1)让n个点中的某个花费每1的距离C费用移动到你的位置,并且带上你以同样代价移动(2)让某点把你横着或者竖着抛出去,假设抛出距离是dis,cost=A*dis+B。求最小花费(n<=1e5)

20tps:暴力,n=2,可以证明如果要单向移动一段距离,那么要么让点带着你,要么抛你,不存在2种方式一起用,不然一定更不优【ax+b+cx<2xa+b && ax+b+cx<2xc,你会发现a<c,a>c矛盾,所以一定更不优】。所以只有3种方式:横走+竖走;横走+竖抛;横抛+竖走。(from Catherine_leah)

100tps正解:Dij大法好,转化成图论。image

其实不用建边,只需要在每个点枚举可以到达的位置,看lu[][][]有没有更新就行。

const int N=1e5+100;
int X,Y,A,B,C,n,stx,sty,edx,edy;
ll dis[510][510],lu[510][510][3];
int dx[5]={0,1,0,-1},dy[5]={1,0,-1,0};
struct node
{
    int x,y,id;ll ds;
    node(){}
    node(int xx,int yy,int idid,ll dsds){x=xx,y=yy,id=idid,ds=dsds;}
    bool operator<(const node&R)const
    {
        return ds>R.ds;
    }
}e[250000+100];
priority_queue<node>q;
deque<node>qq;
int main()
{
	//freopen("","r",stdin);
	//freopen("","w",stdout);
    X=re()+1,Y=re()+1,A=re(),B=re(),C=re();
    n=re();
    _f(i,1,X+1)
    _f(j,1,Y+1)
    {
        dis[i][j]=1e17;
        _f(k,0,2)lu[i][j][k]=1e17;
    }
  
    stx=re()+1,sty=re()+1;dis[stx][sty]=0;
    qq.push_front(node(stx,sty,0,0));
    _f(i,2,n-1)
    {
        int xi=re()+1,yi=re()+1;dis[xi][yi]=0;
        qq.push_front(node(xi,yi,0,0));
    }
    edx=re()+1,edy=re()+1;dis[edx][edy]=0;
    qq.push_front(node(edx,edy,0,0));
    while(!qq.empty())
    {
        node u=qq.front();qq.pop_front();
        _f(i,0,3)
        {
            int xn=u.x+dx[i],yn=u.y+dy[i];
            if(dis[xn][yn]==1e17&&xn<=X&&xn>=1&&yn<=Y&&yn>=1)
            {
                dis[xn][yn]=u.ds+1*C;qq.push_back(node(xn,yn,0,dis[xn][yn]));
            }
        }
    }
    // _f(i,1,X)
    // _f(j,1,Y)
    // chu("dis[%d][%d]:%lld\n",i,j,dis[i][j]);
    q.push(node(stx,sty,2,0));
    while(!q.empty())
    {
        node u=q.top();q.pop();
        if(lu[u.x][u.y][u.id]!=1e17)continue;
        lu[u.x][u.y][u.id]=u.ds;
      // chu("lu[%d][%d][%d]:%lld\n",u.x,u.y,u.id,u.ds);
        if(u.x==edx&&u.y==edy)break;
        if(u.id==2)//如果是被带着移动
        {
            //可以被抛出去
            if(lu[u.x][u.y][0]==1e17)q.push(node(u.x,u.y,0,u.ds+B));
            if(lu[u.x][u.y][1]==1e17)q.push(node(u.x,u.y,1,u.ds+B));
            _f(i,0,3)//可以继续被带着走  优化(上dis)
            {
                int xn=u.x+dx[i],yn=u.y+dy[i];
                if(xn<=X&&xn>=1&&yn<=Y&&yn>=1&&lu[xn][yn][2]==1e17)
                q.push(node(xn,yn,u.id,u.ds+C));
                //如果xn,yn已经在这里被带过一回了,那再从其他地方带着过去一定不是最优
            }
        }
        else//如果飞着呢
        //那就0代表y的加减,1代表x的加减
        {
            for(rint i=u.id;i<4;i+=2)
            {
                int xn=u.x+dx[i],yn=u.y+dy[i];
                if(xn>=1&&xn<=X&&yn<=Y&&yn>=1&&lu[xn][yn][u.id]==1e17)
                {
                    q.push(node(xn,yn,u.id,u.ds+A));
                }
            }
            if(lu[u.x][u.y][2]==1e17)
            q.push(node(u.x,u.y,2,u.ds+dis[u.x][u.y]));
            //现在是放进去,但是不进行更新
        }
    }
    ll ans=min(lu[edx][edy][0],min(lu[edx][edy][1],lu[edx][edy][2]));
    chu("%lld",ans);
	return 0;
}
posted on   HZOI-曹蓉  阅读(59)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示