• 【20170923校内模拟赛】


    所有题目开启-O2优化,评测机效率为4亿左右。


    T1 超重 (overweight)

    Description

    一天小D正在开飞机,当他吃完午饭,机舱里突然响起了警报声,原来是飞机超重了。小D当机立断,开始将机舱里的一些物品扔出窗外。小D的飞机里有n个物品,XY值分别为1n**,他希望扔掉尽量多的东西。但小D持有的两种强迫症让他迟迟无法下手:第一种是他希望所有扔掉的东西中,**任意两个东西的XY值之和不是3的倍数**;第二种是他有m个数字a1am,任意一个扔掉的东西的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
    ",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
    ",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
    ",ans);
    #ifndef Debug
    	fclose(stdin); fclose(stdout);
    #endif
    	return 0;
    }
    
  • 相关阅读:
    python动态网页爬取——四六级成绩批量爬取
    python&MongoDB爬取图书馆借阅记录(没有验证码)
    【Linux】CentOS 7安装与使用,安装jdk1.8,安装mysql
    JavaWeb项目:旅游网站【涉及各种知识】
    【SpringMVC】使用三层架构实现登录,注册。(下篇)
    【SpringMVC】使用三层架构实现登录,注册。(上篇)
    【JSP】el、jstl、MVC、三层架构
    【Tomcat】JSP使用Session、Cookie实现购物车
    HttpServletRequest对象,请求行、请求头、请求体
    【Spring】JdbcTemplate的使用,查询,增、删、改
  • 原文地址:https://www.cnblogs.com/Melacau/p/20170923test.html
Copyright © 2020-2023  润新知