发寿司
Posted smile_to_warm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了发寿司相关的知识,希望对你有一定的参考价值。
发寿司
(测试用例总数:X,1.5 秒 (C/C++),2 秒 (Java)/内存限制:256 M,Stack 1 M)
丽雅开了一家寿司店,为了宣传店铺,她想在开业前准备举办一场活动,邀请N位当地居民免费品尝寿司。
为了增加活动的吸引力,她准备按照如下规则来发寿司。首先,让N名参与活动的人排成一队,每人抽取一张写着编号的纸。(编号可能相同。)如果某个人的编号比他前面以及后面的K个人的排序高(编号越小,排序越低),那么这个人拿到的寿司数量比排序低的人多。
丽雅准备按照上述规则来开展活动,同时希望发出去的寿司数量尽可能少。帮助丽雅求出此次活动需要准备的最少寿司数量。
假设当地有7名居民参加了活动,K为2。当7个人抽取的编号分别为 4、3、2、4、1、4、3时,第5个居民的排序为1,因为其他人的排序都比1高,所以他只能获得一个寿司。对于第3个居民,他前面两个人的排序都比他高,后面两个人中有一个居民抽取了更低的排序1,这个人获得了一个寿司,所以第3个居民会获得两个寿司。第7个居民也会获得两个寿司,因为他前面的两个人中有一个人的排序比他的更低,而那个排序更低的人获得了一个寿司。按这种方式计算,可以得出发给参与者的最少寿司数量为 19,如下所示。
1) 第 1 个居民:获得四个寿司
2) 第 2 个居民:获得三个寿司
3) 第 3 个居民:获得两个寿司
4) 第 4 个居民:获得四个寿司
5) 第 5 个居民:获得一个寿司
6) 第 6 个居民:获得三个寿司
7) 第 7 个居民:获得两个寿司
[限制条件]
1.参与者数量N为介于1到100,000之间的整数。
2.比较排序的人数K为介于1到100,000之间的整数。
3.每个参与者抽取的编号为介于1到N之间的整数。
(1是最低的编号,编号越大,排序越高。)
4.所有参与者至少会获得一个寿司。
[输入]
首先给出测试用例数量T,接着给出T种测试用例。每个测试用例的第一行,给出参与者数量N 和比较排序的人数K。第二行空格区分给出N名参与者抽取的编号。
[输出]
各测试用例输出一行。首先输出“#x”(x为测试用例的编号,从1开始),加一个空格后,输出丽雅需要准备的最少寿司数量。
[输入输出 示例]
(输入)
2
7 2
4 3 2 4 1 4 3
7 1
4 3 2 4 1 4 3
(输出)
#1 19
#2 12
思路分析:
根据题目意思,可知,需要按照排序大小计算,因此先对原数据进行排序,值正序,index逆序
然后求最长递增子序列,第3个用例分析可知,值相同的节点,前面的节点会影响后面的节点,因此需要延迟更新,即,遇到下一个值不同的节点时,再更新当前值的所有节点
用Indexed Tree求当前节点-K~当前节点+K个区间的LIS,加延迟更新
package tree; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.Comparator; import java.util.LinkedList; import java.util.Queue; import java.util.StringTokenizer; /** * 思路分析: * 根据题目意思可知,需要按照排序大小计算,因此先对原数据进行排序,值正序,index逆序 * 然后求最长递增子序列,分析用例可知,值相同的节点,前面的节点会影响后面的节点,因此需要延迟更新,即,遇到下一个值不同的节点时,再更新当前值的所有节点 * 用Indexed Tree求当前节点-K~当前节点+K个区间的LIS,加延迟更新 * @author XA-GDD * */ public class EQ_HandingOutSushi_0615 { static int T,N,K; static int _max_Nval = 100000; static int [][] srcArr = new int [_max_Nval][2]; static int [] lisIdxTree = new int[_max_Nval*4]; static int offset; static Queue<int []> queue = new LinkedList<int[]>(); //延迟更新用Queue,勿使用HashMap,效率太慢 static long ANS; public static void main(String[] args) throws IOException { System.setIn(new FileInputStream("D:\\\\workspace\\\\sw_pro\\\\test_case\\\\sample_input_0615.txt")); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); T = Integer.parseInt(st.nextToken()); for(int testCase = 1; testCase<=T;testCase++) { st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); K = Integer.parseInt(st.nextToken()); ANS=0L; for(int i=0;i<N;i++) { Arrays.fill(srcArr[i], 0); } Arrays.fill(lisIdxTree, 0); st = new StringTokenizer(br.readLine()); for(int i=0;i<N;i++) { srcArr[i][0] = i; srcArr[i][1] = Integer.parseInt(st.nextToken()); } //排序,value正序,index逆序 Arrays.sort(srcArr,0,N, new Comparator<int []>() { @Override public int compare(int[] o1, int[] o2) { if(o1[1]==o2[1]) { return o2[0] - o1[0]; } return o1[1] - o2[1]; } }); //初始化index tree int k=0; while((1<<k)<N) { k++; } offset = 1<<k; int preVal=0; for(int i=0;i<N;i++) { int currVal = srcArr[i][1]; if(currVal!=preVal) { //如果原数组当前节点和前一个节点不相同时,更新与前一个节点相同的所有节点的值 delayedUpdate(); //如果原数组当前节点和前一个节点不相同时,开始记录当前节点的值 queue.clear(); } int start = srcArr[i][0]-K>0?srcArr[i][0]-K:0; int end = srcArr[i][0]+K<offset-1?srcArr[i][0]+K:offset-1; int val = query(start+offset,end+offset); queue.add(new int[] {srcArr[i][0], val+1}); preVal = currVal; } delayedUpdate(); //更新最后一组值 queue.clear(); System.out.printf("#%d %d\\n",testCase,ANS); } } static void delayedUpdate() { while(!queue.isEmpty()) { int obj [] = queue.poll(); update(offset+obj[0],obj[1]); ANS += (long)obj[1]; } } static void update(int index ,int val) { lisIdxTree[index] = val; index = index >>1; while(index>0) { lisIdxTree[index] = Math.max(lisIdxTree[index*2], lisIdxTree[index*2+1]); index = index >>1; } } static int query(int start ,int end) { int res=0; while(start<=end) { if(start%2==1) { res = Math.max(res, lisIdxTree[start]); } if(end%2==0) { res = Math.max(res, lisIdxTree[end]); } start = (start+1)>>1; end = (end-1)>>1; } return res; } }
bzoj 4873: [Shoi2017]寿司餐厅
4873: [Shoi2017]寿司餐厅
2017-10-05
Description
Input
Output
输出共一行包含一个正整数,表示Kiana能获得的总美味度减去花费的总钱数的最大值。
Sample Input
2 3 2
5 -10 15
-10 15
15
Sample Output
当初省选的时候,Day2的T1一看到,额什么东西啊,树+连通块??
T2一个概率,完全GG,T3好像是一个dp,数据还蛮小的x,就是他了,看了半天题目,Day2爆0了,哈哈哈.
这个题现在才知道是网络流,(因为关系复杂,所以先花式建边,分几个步骤
1:如果i=j,令map[i][j]-编号;
2:map[i][j]>0连源点,并和(i+1,j)(i,j-1)相连;
3:map[i][j]<0连汇点,并和(i+1,j)(i,j-1)相连;
建完边跑最小割
用所有正边权和减去最小割就是答案.
w同学汇点选1e7,数组竟然只开了8e4,不re才怪哈哈哈哈哈哈哈哈
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<queue> using namespace std; const int ad=233; const int INT=2333333; int read(){ int an=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(‘0‘<=ch&&ch<=‘9‘){an=an*10+ch-‘0‘;ch=getchar();} return an*f; } bool v[1000+ad]; int a[100+ad],map[100+ad][100+ad],cnt1,cnt=1; int id[100+ad][100+ad],idw[1000+ad]; int f[20000<<2]; int n,m,ans,S,T; struct saber{ int nex,to,wi; }b[20000<<3]; inline void add(int x,int y,int z){ cnt++; b[cnt].nex=f[x]; b[cnt].to=y; b[cnt].wi=z; f[x]=cnt; cnt++; b[cnt].nex=f[y]; b[cnt].to=x; b[cnt].wi=0; f[y]=cnt; } int dis[20000<<2]; queue<int>q; bool bfs(){ while(!q.empty())q.pop(); memset(dis,-1,sizeof(dis)); q.push(S);dis[S]=0; while(!q.empty()){ int x=q.front();q.pop(); for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(dis[v]<0&&b[i].wi){ dis[v]=dis[x]+1; q.push(v); if(v==T)return 1; } } } if(dis[T]>0)return 1; return 0; } int dfs(int x,int li){ if(x==T)return li; int used=li; for(int i=f[x];i;i=b[i].nex){ int v=b[i].to; if(used&&b[i].wi>0&&dis[v]==dis[x]+1){ int re=dfs(v, min(b[i].wi,used) ); b[i].wi-=re; b[i^1].wi+=re; used-=re; if(!re)dis[v]=-23333; } } return li-used; } void prepare(){ n=read();m=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++) for(int j=i;j<=n;j++)map[i][j]=read(); for(int i=1;i<=n;i++) for(int j=i;j<=n;j++)cnt1++,id[i][j]=cnt1; T=cnt1+1000; for(int i=1;i<=n;i++)if(!v[a[i]]){ cnt1++;idw[a[i]]=cnt1; add(cnt1,T,m*a[i]*a[i]);v[a[i]]=1; } for(int i=1;i<=n;i++) for(int j=i;j<=n;j++){ if(i==j){ map[i][j]-=a[i]; add(id[i][j],idw[a[i]],INT); } else { add(id[i][j],id[i][j-1],INT); add(id[i][j],id[i+1][j],INT); } if(map[i][j]<0){ add(id[i][j],T,-map[i][j]); } else { add(S,id[i][j],map[i][j]); ans+=map[i][j]; } } } void dinic(){ while(bfs()){ ans-=dfs(S,INT); } } int main(){ prepare(); dinic(); cout<<ans; return 0; }
by:s_a_b_e_r
省选的时候注意力全在好吃的寿司上w
一道求最大权闭合子图的题,然而建边很难qwq
花式建边:
对于每个取寿司的区间,正的连s,负的连t,边权是区间美味度的绝对值
每个单独的寿司连边的时候额外减去这个寿司的编号(因为要算花费)
每个寿司和这个寿司的编号连一条边,边权INF
每个编号向t连一条边,边权是m*x2
然后跑一遍最大流求出最大权闭合子图就好啦
……以及要明确每个数组的范围qwq
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=109*109,inf=1e7+7; int n,m,cnt=1,p[80000],sum,a[1000+233],tot=1001; int s=0,t=70000,dis[80000],d[233][233],num[233][233]; bool vis[1233]; struct edge{int to,nex,val;}e[20000<<2]; void add(int u,int v,int w) { e[++cnt]=(edge){v,p[u],w}; p[u]=cnt; e[++cnt]=(edge){u,p[v],0}; p[v]=cnt; } queue<int>q; bool bfs() { memset(dis,-1,sizeof(dis)); while(!q.empty())q.pop(); dis[s]=0;q.push(s); while(!q.empty()) { int x=q.front();q.pop(); for(int i=p[x];i;i=e[i].nex) { int v=e[i].to; if(dis[v]<0&&e[i].val) { dis[v]=dis[x]+1; if(v==t)return 1; q.push(v); } } } return 0; } int dfs(int x,int li) { if(x==t)return li; int used=li; for(int i=p[x];i;i=e[i].nex) { int v=e[i].to; if(dis[v]==dis[x]+1&&used&&e[i].val) { int re=dfs(v,min(used,e[i].val)); if(!re)dis[v]=-1; used-=re; e[i].val-=re; e[i^1].val+=re; } } return li-used; } int dinic() { int ans=0; while(bfs()){ans+=dfs(s,inf);} return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); if(vis[a[i]])continue; vis[a[i]]=1;add(a[i],t,m*a[i]*a[i]); } for(int i=1;i<=n;++i) for(int j=i;j<=n;++j) { scanf("%d",&d[i][j]); num[i][j]=++tot; } for(int i=1;i<=n;++i) for(int j=i;j<=n;++j) { if(i==j){ d[i][j]-=a[i]; add(num[i][j],a[i],inf); } else{ add(num[i][j],num[i][j-1],inf); add(num[i][j],num[i+1][j],inf); } if(d[i][j]>=0){add(s,num[i][j],d[i][j]);sum+=d[i][j];} else add(num[i][j],t,-d[i][j]); } cout<<sum-dinic(); return 0; }
by:wypx
以上是关于发寿司的主要内容,如果未能解决你的问题,请参考以下文章