zoukankan      html  css  js  c++  java
  • 9.21 正睿普及2


    2018.9.21 正睿普及2

    时间:3.5h
    期望得分:100+100+20+20
    实际得分:100+100+30+20

    比赛链接

    A Non-max suppression(矩形面积并)

    题目链接

    //阅读理解题。就是排个序,然后求一下矩形面积交/并。
    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 200000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=2005;
    
    int id[N],pos[N];
    bool del[N];
    std::vector<int> ans;
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Matrix
    {
    	int id,pc,x,y,w,h; LL S;
    	int LDx() {return x-w;}
    	int LDy() {return y-h;}
    	void Init() {S=4ll*w*h;}
    	bool operator <(const Matrix &a)const
    	{
    		return pc<a.pc;
    	}
    }mat[N];
    
    inline int read()
    {
    	int now=0,f=1;register char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now*f;
    }
    bool cmp(int i,int j)
    {
    	return mat[i].LDy()==mat[j].LDy()?mat[i].LDx()<mat[j].LDx():mat[i].LDy()<mat[j].LDy();
    }
    bool Check(Matrix a,Matrix b,int aa,int bb)
    {
    	if(pos[aa]>pos[bb]) std::swap(a,b);
    	if(a.LDx()>b.LDx())
    	{
    		int rdx=b.x+b.w, rdy=b.y-b.h;
    		int lux=a.x-a.w, luy=a.y+a.h;
    		rdx=std::min(rdx,a.x+a.w), luy=std::min(luy,b.y+b.h);
    		LL s1=a.S, s2=b.S, sj=1ll*(rdx-lux)*(luy-rdy);
    		return rdx-lux>=0 && s1+s2<3*sj;
    	}
    	else
    	{
    		int ldx=b.x-b.w, ldy=b.y-b.h;
    		int rux=a.x+a.w, ruy=a.y+a.h;
    		rux=std::min(rux,b.x+b.w), ruy=std::min(ruy,b.y+b.h);
    		LL s1=a.S, s2=b.S, sj=1ll*(rux-ldx)*(ruy-ldy);
    		return rux-ldx>=0 && s1+s2<3*sj;
    	}
    }
    
    int main()
    {
    //	freopen("ex_suppresion1.in","r",stdin);
    //	freopen("my.out","w",stdout);
    
    	int n=read();
    	for(int i=1; i<=n; ++i) mat[i]=(Matrix){i,read(),read(),read(),read(),read()},mat[i].Init();
    	std::sort(mat+1,mat+1+n);
    
    	int now=1; mat[n+1].pc=1e7;
    	while(mat[now].pc<600000) ++now;
    	if(now>n) return 0;
    
    	for(int i=now; i<=n; ++i) id[i]=i;
    	std::sort(id+now,id+1+n,cmp);
    	for(int i=now; i<=n; ++i) pos[id[i]]=i;
    	for(int i=n; i>=now; --i)
    	{
    		if(del[i]) continue;
    		ans.push_back(mat[i].id);
    		for(int j=i-1; j>=now; --j)
    		{
    			if(del[j]) continue;
    			if(Check(mat[i],mat[j],i,j)) del[j]=1;//, printf("%d(%d) del %d(%d)
    ",i,mat[i].id,j,mat[j].id);
    		}
    	}
    	std::sort(ans.begin(),ans.end());
    	for(int i=0,l=ans.size(); i<l; ++i) printf("%d ",ans[i]);
    
    	return 0;
    }/*
    6
    700000 456 654 132 321
    520000 255 548 102 99
    905004 600 405 456 210
    650474 511 547 500 45
    957867 200 200 100 150
    741567 1050 451 900 386
    */
    

    B 摩斯电码(DP)

    题目链接

    //很恶心→_→
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define mod 1000000007
    typedef long long LL;
    const int N=1e6+5;
    const char ZZ[5]="1100",RR[5]="010";
    const char ban[4][5]={"1111","0011","0101","1110"};
    
    int n;
    LL f[N][2];
    char s[N];
    
    bool Diff(int p,char c)
    {
    	if(c=='z')
    	{
    		if(p+3>n) return 1;
    		for(int i=0; i<4; ++i) if(s[i+p]!=ZZ[i]) return 1;
    		return 0;
    	}
    	else
    	{
    		if(p+2>n) return 1;
    		for(int i=0; i<3; ++i) if(s[i+p]!=RR[i]) return 1;
    		return 0;
    	}
    }
    bool Check(int p)
    {
    	for(int k=0; k<4; ++k)
    	{
    		for(int i=0; i<5; ++i)
    			if(i==4) return 0;
    			else if(s[p+i]!=ban[k][i]) break;
    	}
    	return 1;
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    
    	scanf("%s",s+1), n=strlen(s+1);
    	f[1][0]=1, f[2][0]=2, f[3][0]=4;
    	if(Diff(1,'z')) f[4][0]=8, f[4][1]=0;
    	else f[4][0]=7, f[4][1]=1;
    	for(int i=5; i<=n; ++i)
    	{
    		f[i][0]=f[i-1][0]+f[i-1][1]+f[i-2][0]+f[i-2][1]+f[i-3][0];
    		if(Diff(i-2,'r')) f[i][0]+=f[i-3][1];
    		if(Check(i-3)){
    			if(Diff(i-3,'z')) f[i][0]+=f[i-4][0]+f[i-4][1];
    			else f[i][1]+=f[i-4][0]+f[i-4][1];
    		}
    		f[i][0]%=mod, f[i][1]%=mod;
    	}
    	printf("%d
    ",(int)((f[n][0]+f[n][1])%mod));
    
    	return 0;
    }
    

    C 并行计算(贪心)

    题目链接

    交换律对应到树上就是可以交换某个点的左右儿子,结合律就是相同的运算符可以进行左旋右旋。
    也就是由一个相同运算符组成的连通块内,可以任意安排顺序。
    计算同一连通块所需要的最少合并时间,可以每次合并两个最小值(x,y),合并后为(max{x,y}+cost),加入堆。
    复杂度(O(nlog n))

    //368ms	45468kb
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define MAXIN 300000
    //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=1e6+5;
    
    int n,P,Q,fa[N],son[N][2];
    char opt[N],IN[MAXIN],*SS=IN,*TT=IN;
    std::priority_queue<int,std::vector<int>,std::greater<int> > q[N];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    int DFS(int x,int anc)
    {
    	if(x>=n) return 0;
    	for(int i=0; i<2; ++i)
    	{
    		int v=son[x][i];
    		if(v>=n) q[anc].push(0);
    		else if(opt[x]==opt[v]) DFS(v,anc);
    		else q[anc].push(DFS(v,v));
    	}
    	if(x==anc)
    	{
    		int cost=opt[x]=='+'?P:Q;
    		while(q[x].size()>1)
    			q[x].pop(), q[x].push(q[x].top()+cost), q[x].pop();
    		return q[x].top();
    	}
    	return 0;
    }
    
    int main()
    {
    	n=read(),P=read(),Q=read();
    	register char c=gc(); for(;c!='+'&&c!='*';c=gc());
    	opt[1]=c; for(int i=2; i<n; ++i) opt[i]=gc();
    	for(int i=1,l=2*n-2,u,v; i<=l; ++i)
    		u=read(), fa[v=read()]=u, son[u][son[u][0]>0]=v;
    	for(int i=1; i<n; ++i) if(!fa[i]) {printf("%d
    ",DFS(i,i)); break;}
    
    	return 0;
    }
    

    D 席位选举(二分 DP 优化状态)

    题目链接

    首先,(a_1,a_n)都要分给第一个政党才最优。这样就把环拆成了一条链。
    二分,假设第一个政党最终至少取得了(mid)个席位。假如我们知道了每个政党的最终得票(v_i'),那么我们可以知道第一个人获得(mid)个席位之前每个人获得的席位数(x_i)。就是解以下不等式的最小整数解:$$frac{v_1'}{(mid-1)+1}geqfrac{v_i'}{x_i+1}$$

    即$$x_igeqfrac{v_i' imes mid}{v_1'}-1x_i=lceilfrac{v_i' imes mid}{v_1'} ceil-1=left[frac{v_i' imes mid+v_1'-1}{v_1'} ight]-1=lfloorfrac{v_i' imes mid-1}{v_1'} floor$$

    如果(sum_{i=2}^nx_ileq m-mid),说明(mid)合法。
    那么现在的问题是判断是否存在一种分配(a_i)的方案使得(sum_{i=2}^nx_ileq m-mid)
    (f_{i,j})表示考虑了前(i)个政党(不包括(1)),留给下一个政党的票数为(j)(a_i)留给(i+1)),此时前(i)个政党的(x_i)之和最小是多少。
    那么枚举(a_i)的分配量,不难得出转移方程。
    复杂度(O(nv^2log m)),期望得分(70)分。

    满分做法:
    (v_i,a_i)的范围变大了,但是(m)的范围没有变。考虑交换两者在DP中的状态。
    (f_{i,j})表示考虑了前(i)个政党(不包括(1)),前(i)个政党的(x_i)之和为(j),此时留给(i+1)的票数最少是多少。
    那么我们求出(f_{n-1})后就知道了第(n)个政党所得票数,然后可以算出(sum_{i=2}^nx_i)
    因为有最终得票的限制,设第(i)个政党从(i-1)得到的票为(f(f[i-1][x'])),当前要得到的票为(y),则有$$frac{v_1'}{(mid-1)+1}geqfrac{v_i+f+y}{x_i+1}$$

    那么(i)最多还能得到的票数为该方程的最大整数解,即$$yleqfrac{v_1' imes(x_i+1)}{mid}-v_i-fy=lfloorfrac{v_1' imes(x_i+1)}{mid} floor-v_i-f$$

    那么留给(i+1)的票数最少为(a_i-y)
    枚举(x_i)不难得出转移方程。
    复杂度(O(nm^2log m)),期望得分(100)

    //1016ms	572kb
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define gc() getchar()
    typedef long long LL;
    const int N=53,M=503,INF=0x3f3f3f3f;
    
    int n,m,v[N],a[N],f[N][M];
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    bool Check(int mid)
    {
    	memset(f,0x3f,sizeof f);
    	f[1][0]=0;
    	int v1=v[1]+a[1]+a[n];
    	for(int i=2,vi=v[i]; i<n; vi=v[++i])
    		for(int j=0,ff; j<=m; ++j)
    			if((ff=f[i-1][j])<INF)
    				for(int k=0,y; j+k<=m; ++k)
    					if((y=1ll*v1*(k+1)/mid-vi-ff)>=0)//>=0!
    						f[i][j+k]=std::min(f[i][j+k],std::max(0,a[i]-y));
    	for(int i=0; i<=m; ++i)//到m啊→_→
    		if(i+std::max(0ll,(1ll*(v[n]+f[n-1][i])*mid-1)/v1)<=m-mid) return 1;
    	return 0;
    }
    
    int main()
    {
    	n=read(),m=read();
    	for(int i=1; i<=n; ++i) v[i]=read();
    	for(int i=1; i<=n; ++i) a[i]=read();
    	int l=1,r=m,mid,ans=0;
    	while(l<=r)
    		if(Check(mid=l+r>>1)) ans=mid,l=mid+1;
    		else r=mid-1;
    	printf("%d
    ",ans);
    
    	return 0;
    }
    

    考试代码

    C

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    typedef long long LL;
    const int N=1e6+5;
    
    int n,Ans,tot,pw[35],At,Mt,tm[3],Enum,H[N],fa[N],son[N][2],val[N],opt[N];
    
    inline int read()
    {
    	int now=0,f=1;register char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now*f;
    }
    void DFS(int x,int &res,int cost)
    {
    	if(!res) return;
    	if(!son[x][0]) val[x]=cost, --res;
    	else DFS(son[x][0],res,cost);
    	if(!son[x][1]) --res;
    	else DFS(son[x][1],res,cost);
    	val[x]=std::max(val[son[x][0]],val[son[x][1]])+cost;
    }
    void Sub1(int c)
    {
    	static int q[N];
    
    	int h=0,t=1,now=1,res=n; q[1]=1;
    	while(h<=t)
    	{
    		int x=q[++h];
    		if(res) q[++t]=++now, son[x][0]=now, --res;
    		if(res) q[++t]=++now, son[x][1]=now, --res;
    	}
    	res=tot-n, DFS(1,res,tm[c]), printf("%d
    ",val[1]);
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    
    //	pw[0]=1;
    //	for(int i=1; i<30; ++i) pw[i]=pw[i-1]<<1;
    
    	n=read()-1,tm[0]=read(),tm[1]=read(),tot=2*n+1;
    	register char c=gc(); for(; c!='+'&&c!='*'; c=gc());
    	opt[1]=c=='+'?0:1;
    	for(int i=2; i<=n; ++i) opt[i]=gc()=='+'?0:1;
    
    	bool f0=0,f1=0;
    	for(int i=1; i<=n; ++i) if(!opt[i]) {f0=1; break;}
    	for(int i=1; i<=n; ++i) if(opt[i]) {f1=1; break;}
    	if(!f0) {Sub1(1); return 0;}
    	else if(!f1) {Sub1(0); return 0;}
    
    //	for(int i=1,u,v; i<=n<<1; ++i)
    //	{
    //		u=read(), fa[v=read()]=u;
    //		if(!son[u][0]) son[u][0]=v;
    //		else son[u][1]=v;
    //	}
    //	int root=1;
    //	for(int i=1; i<=n; ++i) if(!fa[i]) {root=i; break;}
    
    	return 0;
    }
    

    D

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    #define MAXIN 300000
    //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef long long LL;
    const int N=55;
    
    int n,m,A[N],V[N],got[N],Ans;
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    void DFS(int x)
    {
    	if(x>n)
    	{
    		for(int i=1; i<=n; ++i) got[i]=0;
    		for(int t=m; t; --t)
    		{
    			int mx=V[1]/(got[1]+1),p=1;
    			for(int i=2; i<=n; ++i)
    				if(V[i]/(got[i]+1)>mx) mx=V[i]/(got[i]+1), p=i;
    			++got[p];
    		}
    		Ans=std::max(Ans,got[1]);
    	}
    	else if(x!=n) V[x]+=A[x], DFS(x+1), V[x]-=A[x], V[x+1]+=A[x], DFS(x+1), V[x+1]-=A[x];
    	else V[n]+=A[x], DFS(x+1), V[n]-=A[x], V[1]+=A[x], DFS(x+1), V[1]-=A[x];
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	srand(20180921);
    
    	n=read(),m=read();
    	for(int i=1; i<=n; ++i) V[i]=read();
    	for(int i=1; i<=n; ++i) A[i]=read();
    	if(n<=25) DFS(1), printf("%d
    ",Ans);
    	else printf("%d
    ",m);
    
    	return 0;
    }
    
  • 相关阅读:
    L1-050. 倒数第N个字符串
    全排列问题(递归)
    L2-014. 列车调度
    连通 OR 不连通(NOJ 1044)
    数三角形(codevs 3693)
    Min(BZOJ 1441)
    STL中heap用法
    军训分批(codevs 2751)
    团伙(codevs 2597)
    Subsequence(hdu 3530)
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9703771.html
Copyright © 2011-2022 走看看