【20170923校内模拟赛】
2017-09-23 11:02
267 查看
所有题目开启-O2优化,评测机效率为4亿左右。
一天小D正在开飞机,当他吃完午饭,机舱里突然响起了警报声,原来是飞机超重了。小D当机立断,开始将机舱里的一些物品扔出窗外。小D的飞机里有n个物品,XY值分别为1~n,他希望扔掉尽量多的东西。但小D持有的两种强迫症让他迟迟无法下手:第一种是他希望所有扔掉的东西中,任意两个东西的XY值之和不是3的倍数;第二种是他有m个数字a1~am,任意一个扔掉的东西的XY值都不能被这m个数字中的任意一个整除。所以他把这个任务交给了担任僚机的你。
第一行两个正整数n,m。
第二行m个数,表示小D拥有的数字。
输出一个整数,表示小D最多能扔掉多少物品。
4 1
1
0
对于10%的数据,\(n \leq 15\);
对于30%的数据,\(n \leq 5*10^6\);
另外10%的数据,\(m=0\);
另外10%的数据,\(ai<m\);
对于100%的数据,\(,1 \leq n , ai \leq 5*10^8,0 \leq m \leq 15\)。
考虑m=1的情况,显然可以利用解同余方程的方式计算得出[1,n]中数mod 3 = 0,1,2 在去除a1的倍数的情况下的个数。
显然,当m超过1时,可以很简单的利用容斥原理得出结论,时间复杂度为\(O(m*m^2 \log n)\) (log为计算lcm的效率)
答案为\(max\{f[1],f[2]\}+(bool)(f[0])\)
小C喜欢在他的n*m的棋盘上摆弄他的骑士们,每个格子上都有一个骑士,每个骑士有一个XY值vij。现在有人想掀翻他的棋盘用以献祭,小C当然不能苟同,他决定通过摆阵来吓傻对方。他希望留下若干个骑士,使得它们的XY值总和最大。但是处于阵法内的骑士会被施加一些没用的BUFF,每个骑士会攻击它们的控制区域。所以小C希望处于阵法中所有骑士互不攻击。
(一个骑士的控制区域为国际象棋中的“马”从该位置出发走一步能到的位置,如图所示:)
第一行两个正整数n,m。
接下来n行,每行m个整数,表示每个格子上的骑士的XY值。
输出一个整数,表示最终阵法最大的XY值总和。
3 3
1 0 1
2 1 1
0 1 1
5
对于10%的数据,\(n*m \leq 15\);
对于30%的数据,$ n*m \leq 300\(; 另外20%的数据,\) vij>0$;
对于100%的数据,\(1 \leq n, m \leq 20000 , n*m \leq 2000 , |vij| \leq 20000\)。
典型的最大权闭合子图问题,发现马步满足奇偶性不同,于是进行黑白染色之后建图即可。
由于是二分图,强上Dinic即可,时间效率为$O(8 (nm)^\frac{3}{2}) $
小H养了n棵竹笋,每棵竹笋有一个XY值ai。n棵竹笋整齐地排在他家门口的盐地里。冬去春来,又到了万物发春的季节。这一天,小H被一群人逼着去传火,但小H不同意,就开始了逃亡的旅途。他跑到家门口,突然想采集一下门口的竹笋,于是他开始朝盐地走去。由于竹笋们很傲娇,第i棵竹笋会在ti时刻钻出地面,此前它都会一直藏于地下。小H于0时刻站在第1棵竹笋的左边,即0号位置。在每一时刻开始时他都会检测自己脚下是否有钻出地面的竹笋,如果有,则决定是否采摘该竹笋,检测、采摘不需要花费时间;接下来他要对自己下一秒的行动作出决定,他可以决定自己用这一秒的时间移动到下一棵竹笋的位置,或是原地不动,但小H不能往回走。小H有T秒时间在盐地进行如上操作,他希望最后采摘的竹笋的XY值总和最大。
第一行两个正整数n,T。
第二行n个正整数ai,表示每棵竹笋的XY值。
第三行n个正整数ti,表示每棵竹笋何时会钻出地面。
输出一个整数,表示最大的XY值总和。
2 3
1 1
2 2
1
对于5%的数据,\(ti=0\);
对于15%的数据,\(n , T \leq 100\);
对于30%的数据,\(n , T \leq 10000\);
另外20%的数据,\(ai=1\);
对于100%的数据,\(1 \leq n \leq 5*10^5 , 0 \leq T , ti , |ai| \leq10^9\)。
先从ai=1的情况入手: 假设你一直往前走不作停留,那么如果走到一个可采竹笋的地方,那么采下它一定更优。
所以我们枚举小H在哪个地方刚好(因时间不够而)停下来,因为竹笋不消失,可以证明使得地面上能够出现的竹笋最多的策略一定是在0号点等上若干秒,然后一直往前走,最后因为时间不够,恰好在我们枚举的地方停下来。
然后我们发现,枚举一个终点x后,我们在1~x可以采摘的竹笋的ti一定满足小于一个等差数列.
经过各种转化,我们发现随着枚举的终点位置x不断增加(从1~n),可以采摘的最大时刻L是不断降低的,如果转化后的ti(1<=i<=x)低于L,那么这些一定可以被选。
所以我们从1~n一边枚举终点一边做,开一个堆来维护(最大值),一旦堆顶大于L,那么把堆顶弹出,答案减去堆顶的wi值;如果当前枚举的终点小等于L,那么把它插入堆,并加入答案。
权值有负数的情况,不取肯定更优,我们直接把它扔掉即可。所以 时间复杂度为\(O(nlogn)\).
T1 超重 (overweight)
Description
一天小D正在开飞机,当他吃完午饭,机舱里突然响起了警报声,原来是飞机超重了。小D当机立断,开始将机舱里的一些物品扔出窗外。小D的飞机里有n个物品,XY值分别为1~n,他希望扔掉尽量多的东西。但小D持有的两种强迫症让他迟迟无法下手:第一种是他希望所有扔掉的东西中,任意两个东西的XY值之和不是3的倍数;第二种是他有m个数字a1~am,任意一个扔掉的东西的XY值都不能被这m个数字中的任意一个整除。所以他把这个任务交给了担任僚机的你。
Input
第一行两个正整数n,m。
第二行m个数,表示小D拥有的数字。
Output
输出一个整数,表示小D最多能扔掉多少物品。
Sample Input
4 1
1
Sample Output
0
Hint
对于10%的数据,\(n \leq 15\);
对于30%的数据,\(n \leq 5*10^6\);
另外10%的数据,\(m=0\);
另外10%的数据,\(ai<m\);
对于100%的数据,\(,1 \leq n , ai \leq 5*10^8,0 \leq m \leq 15\)。
样例解释
因为1整除任何正整数,所以小D不能扔掉任何东西。Solution
考虑m=1的情况,显然可以利用解同余方程的方式计算得出[1,n]中数mod 3 = 0,1,2 在去除a1的倍数的情况下的个数。
显然,当m超过1时,可以很简单的利用容斥原理得出结论,时间复杂度为\(O(m*m^2 \log n)\) (log为计算lcm的效率)
答案为\(max\{f[1],f[2]\}+(bool)(f[0])\)
Code
#include <stdio.h> #define MN 20 #define R register #define Filename "overweight" #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) inline int read(){ R int x; R bool f; R char c; for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-'); for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0'); return f?-x:x; } int a[MN],n,m;bool used[MN];ll f[3]; inline ll lcm(ll x,ll y){ R ll xx=x,yy=y,r; while (y){ r=x%y;x=y,y=r; }return xx*yy/x; } inline void dfs(ll res,int k,int to,int lst,int opt){ if (k>to){ R int tmp=n/res;if (res%3){ if (res%3==1){ f[1]+=opt*(tmp/3+(tmp%3?1:0)); f[2]+=opt*(tmp/3+(tmp%3>1?1:0)); f[0]+=opt*(tmp/3); }else{ f[2]+=opt*(tmp/3+(tmp%3?1:0)); f[1]+=opt*(tmp/3+(tmp%3>1?1:0)); f[0]+=opt*(tmp/3); } }else f[0]+=opt*tmp; return; }if (lst+(to-k)+1>m) return; for (R int i=lst+1; i<=m; ++i) if (!used[i]&&lcm(res,a[i])<=n) {used[i]=1;dfs(lcm(res,a[i]),k+1,to,i,opt);used[i]=0;} } int main(){ #ifndef Debug freopen(Filename".in","r",stdin); freopen(Filename".out","w",stdout); #endif n=read(),m=read();f[0]=n/3,f[1]=n/3+(n%3?1:0),f[2]=n/3+(n%3>1?1:0); for (R int i=1; i<=m; ++i) a[i]=read();for (R int i=1; i<=m; ++i) dfs(1,1,i,0,(i%2?-1:1)); printf("%lld\n",max(f[1],f[2])+((bool)f[0])); #ifndef Debug fclose(stdin); fclose(stdout); #endif return 0; }
T2 献祭(sacrifice)
Description
小C喜欢在他的n*m的棋盘上摆弄他的骑士们,每个格子上都有一个骑士,每个骑士有一个XY值vij。现在有人想掀翻他的棋盘用以献祭,小C当然不能苟同,他决定通过摆阵来吓傻对方。他希望留下若干个骑士,使得它们的XY值总和最大。但是处于阵法内的骑士会被施加一些没用的BUFF,每个骑士会攻击它们的控制区域。所以小C希望处于阵法中所有骑士互不攻击。
(一个骑士的控制区域为国际象棋中的“马”从该位置出发走一步能到的位置,如图所示:)
Input
第一行两个正整数n,m。
接下来n行,每行m个整数,表示每个格子上的骑士的XY值。
Output
输出一个整数,表示最终阵法最大的XY值总和。
Sample Input
3 3
1 0 1
2 1 1
0 1 1
Sample Output
5
Hint
对于10%的数据,\(n*m \leq 15\);
对于30%的数据,$ n*m \leq 300\(; 另外20%的数据,\) vij>0$;
对于100%的数据,\(1 \leq n, m \leq 20000 , n*m \leq 2000 , |vij| \leq 20000\)。
样例解释
选取(2,1)、(2,2)、(2,3)、(3,2)四个格子上的骑士,2+1+1+1=5。Solution
典型的最大权闭合子图问题,发现马步满足奇偶性不同,于是进行黑白染色之后建图即可。
由于是二分图,强上Dinic即可,时间效率为$O(8 (nm)^\frac{3}{2}) $
Code
#include <stdio.h> #include <string.h> #define R register #define MN 20005 #define ME 200005 #define S 0 #define T 20001 #define inf 0x3f3f3f3f #define min(a,b) ((a)<(b)?(a):(b)) #define Filename "sacrifice" inline int read(){ R int x; R bool f; R char c; for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-'); for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0'); return f?-x:x; } const int fx[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}}; int n,m,sum,to[ME],nxt[ME],head[MN],cap[ME],que[MN],lev[MN],iter[MN],cnt=1;bool used[MN]; inline void ins(int x,int y,int v){to[++cnt]=y,nxt[cnt]=head[x],cap[cnt]=v,head[x]=cnt;} inline void insw(int x,int y){ins(x,y,inf);ins(y,x,inf);} inline void insw(int x,int y,int v){ins(x,y,v);ins(y,x,0);} inline bool bfs(){ memset(lev,-1,sizeof(lev)); R int h=0,t=1;que[1]=S;lev[S]=0; while(h<t){ R int u=que[++h]; for (R int i=head[u]; i; i=nxt[i]) if (cap[i]&&lev[to[i]]==-1){ lev[to[i]]=lev[u]+1; que[++t]=to[i]; } } memcpy(iter,head,sizeof(head)); return lev[T]!=-1; } inline int dfs(int u,int f){ if (u==T) return f; R int used=0;for (R int &i=iter[u]; i; i=nxt[i]) if (lev[to[i]]==lev[u]+1&&cap[i]){ R int w=dfs(to[i],min(f-used,cap[i])); used+=w;cap[i]-=w;cap[i^1]+=w; if (used==f) return f; } if (!used) lev[u]=-1; return used; } inline int dinic(){ R int flow=0,tmp; while(bfs())do flow+=(tmp=dfs(S,inf)); while(tmp); return flow; } inline bool check(int x,int y) {return x>=1&&x<=n&&y>=1&&y<=m;} int main(){ #ifndef Debug freopen(Filename".in","r",stdin); freopen(Filename".out","w",stdout); #endif n=read(),m=read(); for (R int i=1; i<=n; ++i) for (R int j=1; j<=m; ++j){ R int x=read(); if (x<=0) continue; else sum+=x; if (i+j&1) insw(S,(i-1)*m+j,x); else insw((i-1)*m+j,T,x); } for (R int i=1; i<=n; ++i) for (R int j=1; j<=m; ++j) if (i+j&1) for (R int k=0,ni,nj; k<8; ++k) if (check(ni=i+fx[k][0],nj=j+fx[k][1])) insw((i-1)*m+j,(ni-1)*m+nj,inf); printf("%d\n",sum-dinic()); #ifndef Debug fclose(stdin); fclose(stdout); #endif return 0; }
T3 欲望(urge)
Description
小H养了n棵竹笋,每棵竹笋有一个XY值ai。n棵竹笋整齐地排在他家门口的盐地里。冬去春来,又到了万物发春的季节。这一天,小H被一群人逼着去传火,但小H不同意,就开始了逃亡的旅途。他跑到家门口,突然想采集一下门口的竹笋,于是他开始朝盐地走去。由于竹笋们很傲娇,第i棵竹笋会在ti时刻钻出地面,此前它都会一直藏于地下。小H于0时刻站在第1棵竹笋的左边,即0号位置。在每一时刻开始时他都会检测自己脚下是否有钻出地面的竹笋,如果有,则决定是否采摘该竹笋,检测、采摘不需要花费时间;接下来他要对自己下一秒的行动作出决定,他可以决定自己用这一秒的时间移动到下一棵竹笋的位置,或是原地不动,但小H不能往回走。小H有T秒时间在盐地进行如上操作,他希望最后采摘的竹笋的XY值总和最大。
Input
第一行两个正整数n,T。
第二行n个正整数ai,表示每棵竹笋的XY值。
第三行n个正整数ti,表示每棵竹笋何时会钻出地面。
Output
输出一个整数,表示最大的XY值总和。
Sample Input
2 3
1 1
2 2
Sample Output
1
Hint
对于5%的数据,\(ti=0\);
对于15%的数据,\(n , T \leq 100\);
对于30%的数据,\(n , T \leq 10000\);
另外20%的数据,\(ai=1\);
对于100%的数据,\(1 \leq n \leq 5*10^5 , 0 \leq T , ti , |ai| \leq10^9\)。
样例解释
小H只能采到第1个或第2个竹笋。Solution
先从ai=1的情况入手: 假设你一直往前走不作停留,那么如果走到一个可采竹笋的地方,那么采下它一定更优。
所以我们枚举小H在哪个地方刚好(因时间不够而)停下来,因为竹笋不消失,可以证明使得地面上能够出现的竹笋最多的策略一定是在0号点等上若干秒,然后一直往前走,最后因为时间不够,恰好在我们枚举的地方停下来。
然后我们发现,枚举一个终点x后,我们在1~x可以采摘的竹笋的ti一定满足小于一个等差数列.
经过各种转化,我们发现随着枚举的终点位置x不断增加(从1~n),可以采摘的最大时刻L是不断降低的,如果转化后的ti(1<=i<=x)低于L,那么这些一定可以被选。
所以我们从1~n一边枚举终点一边做,开一个堆来维护(最大值),一旦堆顶大于L,那么把堆顶弹出,答案减去堆顶的wi值;如果当前枚举的终点小等于L,那么把它插入堆,并加入答案。
权值有负数的情况,不取肯定更优,我们直接把它扔掉即可。所以 时间复杂度为\(O(nlogn)\).
Code
#include <stdio.h> #define MN 500005 #define R register #define Filename "urge" #define ll long long #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) inline int read(){ R int x; R bool f; R char c; for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-'); for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0'); return f?-x:x; } struct node{ int pos,val; inline bool operator >(const node &b)const{ return pos>b.pos; } }; class heap{ private: node hp[MN<<1];int sz; inline void swap(node &a,node &b){R node t=b; b=a; a=t;} public: inline void clear(){sz=0;} inline node get(){ R node tmp=hp[1];hp[1]=hp[sz--]; R int k=1;while((k<<1)<sz&&(hp[k<<1]>hp[k]||hp[k<<1|1]>hp[k])) if (hp[k<<1]>hp[k<<1|1]){ swap(hp[k<<1],hp[k]); k<<=1; }else{ swap(hp[k<<1|1],hp[k]);k=k<<1|1; } if ((k<<1)==sz&&hp[k<<1]>hp[k]) swap(hp[k<<1],hp[k]); return tmp; } inline void in(node x){ R int k=++sz;hp[k]=x; while(k>1&&hp[k]>hp[k>>1]) swap(hp[k],hp[k>>1]),k>>=1; } inline node top(){return hp[1];} inline bool empty(){return !sz;} }heap; int n,m,val[MN];ll ans,res; int main(){ #ifndef Debug freopen(Filename".in","r",stdin); freopen(Filename".out","w",stdout); #endif n=read(),m=read(); for (R int i=1; i<=n; ++i) val[i]=read(); for (R int i=1,top=m-1; i<=min(n,m-1); ++i){ --top; R int x=read()-i; while(!heap.empty()&&heap.top().pos>top) res-=heap.get().val; if (x<=top&&val[i]>0) heap.in((node){x,val[i]}),res+=val[i]; ans=max(ans,res); }printf("%lld\n",ans); #ifndef Debug fclose(stdin); fclose(stdout); #endif return 0; }
相关文章推荐
- 2016.10.18出题人丁明朔校内模拟赛反思
- 【20171018校内模拟赛】
- 【20171029校内模拟赛】无题
- 20171108校内模拟赛
- 5.13 校内模拟赛
- 2010年9月22号校内ACM省赛前模拟赛教师总结外加部分结题报告
- 【20170528校内模拟赛】
- 2018.10.17校内模拟赛:T2神光
- 【20170915校内模拟赛】
- 【20170902校内模拟赛】
- 20171107校内模拟赛
- 【20170920校内模拟赛】小Z爱学习
- NOIP校内模拟赛1
- 2017.8.15 校内模拟赛
- 【20170521校内模拟赛】热爱生活的小Z
- 2017.9.2 校内模拟赛
- 2017.9.17校内noip模拟赛解题报告
- 【20170604校内模拟赛】香蕉
- 【20170906校内模拟赛】
- 工大校内常用ftp收藏