首页 > 其他分享 >USACO2023 一月月赛 Platinum 2

USACO2023 一月月赛 Platinum 2

时间:2023-02-02 00:55:14浏览次数:47  
标签:Platinum USACO2023 魔力 size2 月赛 int mid long kk

受到样例的第四个询问启发,我们可以发现一个性质:一开始先让魔力积累,然后肯定是在最晚的那个时候,我们去把魔力池里该取的魔力取走,而不是一开始就和一个无头苍蝇一样在图上乱走。

比如你像无头苍蝇一样走了一个路径:\(1\rightarrow3\rightarrow2\rightarrow4\rightarrow2\rightarrow3\rightarrow4\rightarrow2\rightarrow3\),那你会发现我还不如先一直待在一号点,然后快结束的时候,我再去走\(1\rightarrow4\rightarrow2\rightarrow3\)这样的路径来的好,同时,我即使途径\(3\)号点和\(2\)号点,我一开始也可以假装没取,反正之后我还要再经过它。

由于有我们上面的发现,现在我可以假设每个点都只会取走一次魔力值,\(N\)很小,所以可以状压\(S\)表示取走了\(S\)池子里的魔力值。

任选一个时刻作为终点时刻,不妨假设是\(x\)。

\(f[i][S]\)表示在最后时刻\(x\)我们位于\(i\)号点,走过了\(S\)这些点,取得的最大魔力值是多少。用\(sum[S]\)表示\(S\)集合单位时间积累的魔力之和,用\(dist[a][b]\)表示\(a\)到\(b\)的最短路径和。

\(f[i][S]=max(f[j][S-\{i\}]-sum[S-\{i\}]\times dist[j][i])+m[i]x\)

你会发现,对于一个状态\(S\),它可能有一些点被推到负时刻去了,这会不会对答案产生不利呢?答案是不会,因为对于推到负时刻去的情况,我们把这几个点给删除,会使得更小的集合\(S'\)答案更优。

对于询问时刻\(s\),我们要做的是找出一个状态\(f[e][S]\),给这个状态加上\((s-x)\times sum[S]\),求最大值,直接枚举\(S\)会超时,所以我要用数据结构来维护一次函数极值,这个过程很简单,每次往数据结构中插入一条线,将他和已经在数据结构中的线构成的交点进行比较,将小于它的一连串交点pop出去,换上属于自己的交点,找小于它的交点用二分法。也可以用类似求凸包的方法,将所有的直线按斜率升序排列,用栈维护每个直线掌管的区间,可以做到\(O(n2^n)\)。

由于\(x\)时刻可以任选,所以这里直接选取\(x=0\)进行\(dp\)

代码:

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

const int maxn = 28;

long long a[maxn];
long long dist[maxn][maxn];

long long f[19][(1<<18)+10],sum[(1<<18)+10];

struct line{
    long long k,b;
};

int cmp(line alpha,line beta){
    if(alpha.k == beta.k) return alpha.b > beta.b;
    else return alpha.k < beta.k;
}

struct HotterColder{
    line l[(1<<18)+10];

    struct node{
	int l,r;
	int nb; // left right number
    }p[(1<<18)+10];
    int size,size2;
    
    long long getdata(int now,int x){
	return l[now].k*x+l[now].b;
    }
    void getres(){
	sort(l+1,l+size+1,cmp);
	for(int i=1;i<=size;i++){
	    if(i != 1 && l[i].k == l[i-1].k) continue;
	    while(size2 && getdata(i,p[size2].l) >= getdata(p[size2].nb,p[size2].l)){
		size2--;
	    }
	    if(size2 == 0){
		p[++size2] = (node){0,(int)1e9,i};
	    }else{
		int kk = p[size2].nb;
		long long bhpts = (l[kk].b-l[i].b)/(l[i].k-l[kk].k)+((l[kk].b-l[i].b)%(l[i].k-l[kk].k)!=0);
		if(bhpts>1e9) continue;
		p[size2].r = bhpts-1;
		p[++size2] = (node){bhpts,(int)1e9,i};
	    }
	}
    }
    void add(int k,long long b){
	l[++size] = (line){(long long)k,b};
    }
    long long query(int x,int ll,int r){
	int mid = (ll+r)/2;
	if(p[mid].l <= x && p[mid].r >= x){
	    return getdata(p[mid].nb,x);
	} else if(p[mid].l > x) return query(x,ll,mid-1);
	else return query(x,mid+1,r);
    }
}H[20];

int main(){
    int n,m;
    cin >> n >> m;
    for(int i=1;i<=n;i++){
	cin >> a[i];
    }
    for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	    dist[i][j] = 1e9+1; //注意这个上界对求真正的dist是远远不够的,但这道题这样就足够了
    //想一想原因^o^
    for(int i=1;i<=n;i++) dist[i][i] = 0;
    for(int i=1;i<=m;i++){
	int u,v,w; cin >> u >> v >> w;
	dist[u][v] = w;
    }

    //floyd
    for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++)
		dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]);

    for(int S=0;S<(1<<n);S++){
	for(int i=1;i<=n;i++){
	    f[i][S] = -3e18;
	    if((1<<i-1)&S){
		sum[S] = sum[S-(1<<i-1)]+a[i];
	    }
	}
    }

    //dp,假设终止点为0
    for(int i=1;i<=n;i++) f[i][(1<<i-1)] = a[i]*0;
    for(int S=1;S<(1<<n);S++){
	for(int i=1;i<=n;i++){
	    if((1<<i-1)&S){
		for(int j=1;j<=n;j++){
		    if(((1<<j-1)&S) && i!=j && dist[j][i]<2e15){
			f[i][S] = max(f[i][S],f[j][S-(1<<i-1)]-sum[S-(1<<i-1)]*dist[j][i]);
		    }
		}
	    }
	}
    }
    
    int q; cin >> q;
    for(int i=1;i<=n;i++){//设计构建维护一次函数的极值结构
	for(int j=0;j<(1<<n);j++){
	    if((1<<i-1)&j) H[i].add(sum[j],f[i][j]);
	}
	H[i].getres();
    }
    for(int i=1;i<=q;i++){
	long long s,e; cin >> s >> e;
	long long ans = H[e].query(s,1,H[e].size2);//直接查询
	/*long long ans = 0;
	for(int j=0;j<(1<<n);j++){
	    if((1<<e-1)&j)
		ans = max(ans,f[e][j]+s*sum[j]);
		}*/
	cout<<ans<<endl;
    }
}

标签:Platinum,USACO2023,魔力,size2,月赛,int,mid,long,kk
From: https://www.cnblogs.com/Menhera/p/17084604.html

相关文章

  • 牛客小白月赛65
    题目地址说实话题目质量一次比一次好。A注意到a和b的数量不能为负否则他们张成的空间为他们最大公约数的倍数。这里枚举ab的数量1~1000即可。B实际上是字符串匹配问......
  • USACO2023Jan游记
    由于学校要求,过来打USACO。似乎要求起码升到白金?由于是第一次打,只有从铜组开始了。Brouze简单题,就给核心代码。30minAK。Leadershttp://usaco.org/current/index.......
  • USACO2023 Bronze 题解
    Problem1.Leaders\(\mathcal{Farmer\John}\)共有\(n\)头奶牛,品种用字符\(\mathsf{G}\)或\(\mathsf{H}\)表示。每一头牛有一个管辖区间\([i,E_i]\)称一头......
  • 月赛两题
    P8968觅光称包含目标点\(u\)的那颗子树为目标子树,结论就是只要非目标子树容量充足,后手可以至少将一半的球扔到非目标子树里去。而且只要先手只扔正电球就可以达到这个......
  • 牛客小白月赛65——D-牛牛取石子
    链接:https://ac.nowcoder.com/acm/contest/49888/D来源:牛客网牛牛和牛妹在玩游戏,他们的游戏规则是这样的:一共有两堆石子,第一堆有aaa个,第二堆有bbb个,牛牛和牛妹轮流取......
  • YACS 2022年12月月赛 乙组 T1 拼接单词 题解
    一道结论题,代码相当的短。我们先来考虑会拼出重复的情况:那必定是第一个字符串里有一个$a$(其他的也行),第二个也有一个$a$。那么我们就可以选择拿第一个字符串$a$前面的......
  • YACS 2022年12月月赛 乙组 T2 八进制小数 题解
    纪念一下,两件事。$1.$打$YACS$一年了,时间过得好快啊。$2.$第一次$AK$乙组。高精板子。$8$进制转十进制,很简单。小数部分第一位的数字乘上$8^{-1}$,第二位就乘上......
  • 牛客小白月赛65D题 牛牛取石头 题解
    原题链接第一眼看到这道题,其实很容易会联想到经典的bashgame问题这道题并没有巴什博弈那么复杂,但也算一道比较新颖的博弈论题吧还是很适合作为一道博弈论入门题的题......
  • 牛客小白月赛64 D-Karashi的树 I(dfs)
    https://ac.nowcoder.com/acm/contest/49244/D每个点的价值是它到根节点的路径上所有节点的所有点权和(包括它自己)点数其实也就是从根节点数这棵子树有多少个子节点......
  • 牛客小白月赛64 C-Karashi的生日蛋糕(思维)
    https://ac.nowcoder.com/acm/contest/49244/C题目大意:Karashi决定将水果摆放成n圈,第i圈必须有i个水果。一共k个人,Karashi需要把蛋糕沿半径均分成k块,任意两块蛋糕包含......