zoukankan      html  css  js  c++  java
  • 【CodeChef】August Challenge 2019 Div2 解题报告

    点此进入比赛

    (T1):Football(点此看题面

    大致题意:(max(20a_i-10b_i,0))

    送分题不解释。

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 150
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n,a[N+5],b[N+5];
    int main()
    {
    	RI Tt,i,x,y,ans;scanf("%d",&Tt);W(Tt--)
    	{
    		for(scanf("%d",&n),ans=0,i=1;i<=n;++i) scanf("%d",a+i);
    		for(i=1;i<=n;++i) scanf("%d",b+i),Gmax(ans,20*a[i]-10*b[i]);//统计答案
    		printf("%d
    ",ans);
    	}return 0;
    }
    

    (T2):Distribute Apples(点此看题面

    大致题意: 有两种分苹果方法,一种把(n)个苹果平均分到(k)个盒子中,一种每次在一个盒子中放(k)个苹果放(frac nk)次,判断两种放法结果是否一样。

    考虑苹果总数是一样的,因此只要第二种方法能做到平均分配,结果就是一样的。

    而第二种方法做到平均分配,就说明(k|frac nk)

    判一下即可。

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 150
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    long long n,k;
    int main()
    {
    	RI Tt,i,x,y,ans;scanf("%d",&Tt);W(Tt--)
    		scanf("%lld%lld",&n,&k),puts((n%k||(n/k)%k)?"YES":"NO");//判断k|(n/k)
    	return 0;
    }
    

    (T3):Dilemma (点此看题面

    大致题意: 给你一个(01)序列,每次能把一个为(1)的位置变成(-1),将其相邻的(0)变成(1)(1)变成(0)。问是否能把所有位置变成(-1)

    结论题?

    首先,可以发现,如果把若干个连续(0)换成一个(0),答案不变,如(101)(1001)

    其次,可以发现,若只有长度为偶数的连续(1)的序列,是不可以的,如(1111)(01101111110)。但只要有一个长度为奇数的连续(1)的序列,就可以了,如(111011)。也就是说,除去长度为偶数的连续(1)的序列,答案不变。

    也就是说,我们只需考虑长度为奇数的连续(1)的序列。

    然后画图找找规律,就可以发现当有奇数个长度为奇数的连续(1)的序列时可以,否则不可以。

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n;char s[N+5];
    int main()
    {
    	RI Tt,i,t=0,res=0;scanf("%d",&Tt);W(Tt--)
    	{
    		for(scanf("%s",s),n=strlen(s),t=res=i=0;i^n;++i)
    			s[i]&1?(t^=1):(res^=t,t=0);puts(res^t?"WIN":"LOSE");//t统计当前连续1序列的奇偶性,res统计长度为奇数的连续1的序列的个数的奇偶性
    	}return 0;
    }
    

    (T4):Zombie and the Caves(点此看题面

    大致题意: 给你个数组(C)以及一个空序列,对于每个(i),把序列中第(i-C_isim i+C_i)个位置都加上(1),再给你一个序列,问两个序列中的数是否能一一匹配。

    我们先差分求出这个序列,然后排序比较两个序列即可。

    这里我用了桶排。

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define min(x,y) ((x)<(y)?(x):(y))
    #define max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    int n,s[N+5],p[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		char c,*A,*B,FI[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    int main()
    {
    	RI Tt,i,x,f;F.read(Tt);W(Tt--)
    	{
    		for(F.read(n),i=1;i<=n;++i) s[i]=p[i]=0;//清空
    		for(i=1;i<=n;++i) F.read(x),++s[max(i-x,1)],--s[min(i+x,n)+1];//差分
    		for(i=1;i<=n;++i) (s[i]+=s[i-1])<=n&&++p[s[i]];//求出序列并存入桶中
    		for(f=i=1;i<=n;++i) F.read(x),(x>n||!p[x]--)&&(f=0);puts(f?"YES":"NO");//判断是否可以一一匹配
    	}return 0;
    }
    

    (T5):Guddu and his Mother(点此看题面

    大致题意: 给你一个序列,求有多少组((i,j,k))满足(xor_{x=i}^{j-1}a_x=xor_{x=j}^ka_x)

    首先容易发现,对于一组((i,k)),若其满足(xor_{x=i}^ka_x=0),则对于满足(i<jle k)的任意一组((i,j,k))都是一组合法解,即有(k-i)组合法解。

    若我们记(s_i=xor_{x=1}^ia_x),就相当于(s_{i-1} xor s_k=0),即(s_{i-1}=s_k)时,有(k-i)组合法解。

    也就是当(s_i=s_k)时,有(k-i-1=(k-1)-i)组合法解。

    所以我们开两个(map)(p_x)表示之前所有满足(s_i=x)(i)的和,(g_x)表示之前满足(s_i=x)(i)的个数。

    那么我们枚举(i),就可以更新(ans)加上(g_{s_i}(i-1)-p_{s_i})

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define LL long long
    #define min(x,y) ((x)<(y)?(x):(y))
    #define max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    int n,s[N+5];map<int,LL> p,g;
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		char c,*A,*B,FI[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    int main()
    {
    	RI Tt,i,x;LL ans;F.read(Tt);W(Tt--)
    	{
    		ans=0,p.clear(),g.clear(),p[0]=0,g[0]=1;//清空
    		for(F.read(n),i=1;i<=n;++i) F.read(x),//读入
    			s[i]=s[i-1]^x,ans+=1LL*g[s[i]]*(i-1)-p[s[i]],p[s[i]]+=i,++g[s[i]];//统计前缀和,更新答案,更新map
    		printf("%lld
    ",ans);//输出答案
    	}return 0;
    }
    

    (T6):Encoding(点此看题面

    大致题意:(F(x))(x)十进制数位中每段连续相同数字只保留最高位、其余位替换为(0)后的值,求(sum_{i=l}^rF(i))

    显然数位(DP)

    我们设(f_{x,lst})(g_{x,lst})分别表示右数第(x)位、上一个数为(lst)时的答案和情况数。

    考虑记忆化搜索。

    对于答案,转移时先将后继状态的(f)求和,然后若枚举到这一位的值(y)不等于(lst),就将答案加上后继状态的(g)(y*10^x)

    对于情况数,直接将后继状态的(g)求和即可。

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define X 1000000007
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int nl,nr;char L[N+5],R[N+5];
    class DigitalDP
    {
    	private:
    		#define Pr pair<int,int>
    		#define mp make_pair
    		#define fir first
    		#define sec second
    		int v[N+5],tn[N+5],f[N+5][10],g[N+5][10];
    		I Pr DP(CI x,CI lst,CI p)//数位DP
    		{
    			RI i,lim=p?v[x]:9;Pr t,k=mp(0,0);
    			if(!x) return mp(0,1);if(!p&&~f[x][lst]) return mp(f[x][lst],g[x][lst]);//若求过答案,直接返回
    			for(i=0;i<=lim;++i) t=DP(x-1,i,p&&(i==lim)),//枚举这一位填的数,处理后继状态
    				Inc(k.fir,t.fir),Inc(k.sec,t.sec),i^lst&&(k.fir=(1LL*tn[x]*i%X*t.sec+k.fir)%X);//统计答案和情况数
    			return f[x][lst]=k.fir,g[x][lst]=k.sec,k;//记忆化,返回答案
    		}
    	public:
    		I DigitalDP() {RI i;for(tn[1]=1,i=2;i<=N;++i) tn[i]=10LL*tn[i-1]%X;}//初始化10的幂
    		I int GetAns(CI x,char *s)
    		{
    			RI i,ans=0;Pr t;for(i=x;i;--i) v[i]=s[x-i]&15;memset(f,-1,sizeof(f));//清空
    			for(i=0;i<=v[x];++i) t=DP(x-1,i,i==v[x]),ans=(1LL*tn[x]*i%X*t.sec+t.fir+ans)%X;//枚举最高位,这个写法有点蠢啊
    			return ans;
    		}
    }D;
    int main()
    {
    	RI Tt,p;scanf("%d",&Tt);W(Tt--)
    	{
    		scanf("%d%s%d%s",&nl,L,&nr,R);p=nl-1;W(L[p]=='0') L[p--]='9';--L[p];//将L-1差分
    		printf("%d
    ",(D.GetAns(nr,R)-D.GetAns(nl,L)+X)%X);//求答案
    	}return 0;
    }
    

    (T7):Chef and Gordon Ramsay(点此看题面

    大致题意: 求有多少对((x,y,z))满足(y)(x)(z)树上最短路径上,且满足给定的相对大小。

    考虑一下线段树合并+大分类讨论。

    我们先线段树合并,用值域线段树存下每个子树内的所有值。

    然后,枚举(y),并对(y)从大到小的相对排名,以及路径完全在子树内还是部分在子树外,分类讨论:

    • (y)相对排名为(1),求出子树内大于(y)的数的个数乘子树外大于(y)的数的个数(子树外的可以差分),并枚举子节点加上该儿子的子树内大于(y)的数的个数乘其他儿子子树内大于(y)的数的个数(其他儿子的可以差分)除以(2)
    • (y)相对排名为(2),求出子树内大于(y)的数的个数乘子树外小于(y)的数的个数加上求出子树内小于(y)的数的个数乘子树外大于(y)的数的个数,并枚举子节点加上该儿子的子树内小于(y)的数的个数乘其他儿子子树内大于(y)的数的个数。
    • (y)相对排名为(3),与相对排名为(1)类似,略。

    注意卡常,有些用的很多次的值不要每次都到线段树上去查询,可以直接存下来。

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define LN 20
    #define LL long long
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    using namespace std;
    int n,ee,lnk[N+5],Sz[N+5],p[4];LL ans;struct edge {int to,nxt;}e[N<<1];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		char c,*A,*B,FI[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    template<int SZ,int PS> class SegmentTree//线段树
    {
    	private:
    		#define LT l,mid,O[rt].S[0]
    		#define RT mid+1,r,O[rt].S[1]
    		#define PU(x) (O[x].V=O[O[x].S[0]].V+O[O[x].S[1]].V)
    		int n,Nt,Rt[SZ+5];struct node {int V,S[2];}O[PS+5];
    		I void Ins(CI v,CI l,CI r,int& rt)//单点修改
    		{
    			if(!rt&&(rt=++Nt,O[rt].S[0]=O[rt].S[1]=0),l==r) return (void)(O[rt].V=1);
    			RI mid=l+r>>1;v<=mid?Ins(v,LT):Ins(v,RT),PU(rt);
    		}
    		I int Qry(CI x,CI y,CI l,CI r,CI rt)//区间求和
    		{
    			if(!rt) return 0;if(x<=l&&r<=y) return O[rt].V;RI mid=l+r>>1;
    			return (x<=mid?Qry(x,y,LT):0)+(y>mid?Qry(x,y,RT):0);
    		}
    		I int Merge(CI l,CI r,CI x,CI y)//线段树合并
    		{
    			if(!x||!y) return x+y;RI rt=++Nt;if(l==r) return (O[rt].V=O[x].V+O[y].V);RI mid=l+r>>1;
    			O[rt].S[0]=Merge(l,mid,O[x].S[0],O[y].S[0]),O[rt].S[1]=Merge(mid+1,r,O[x].S[1],O[y].S[1]);
    			return PU(rt),rt;
    		}
    	public:
    		I void Init(CI _n) {Nt=0,n=_n;for(RI i=1;i<=n;++i) Rt[i]=0;}
    		I void Ins(CI id,CI v) {Ins(v,1,n,Rt[id]);}
    		I int Qry(CI id,CI l,CI r) {return Qry(l,r,1,n,Rt[id]);}
    		I void Merge(CI x,CI y) {Rt[x]=Merge(1,n,Rt[x],Rt[y]);}
    };SegmentTree<N,N*LN<<1> S;
    I void dfs(CI x,CI lst=0)
    {
    	RI i;for(Sz[x]=1,S.Ins(x,x),i=lnk[x];i;i=e[i].nxt)//处理子树,合并子树线段树
    		e[i].to^lst&&(dfs(e[i].to,x),Sz[x]+=Sz[e[i].to],S.Merge(x,e[i].to),0);
    	LL res=0;RI t,t1=S.Qry(x,1,x-1),t2=Sz[x]-t1-1;
    	if(p[2]==1)//若y相对排名为1
    	{
    		ans+=1LL*(n-x-t2)*t2;//部分在子树外
    		for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&//完全在子树内
    			(t=S.Qry(e[i].to,x+1,n),res+=1LL*(t2-t)*t);
    	}
    	else if(p[2]==2)//若y相对排名为2
    	{
    		ans+=1LL*(n-x-t2)*t1+1LL*(x-1-t1)*t2;//部分在子树外
    		for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&//完全在子树内
    			(t=S.Qry(e[i].to,x+1,n),res+=1LL*(t2-t)*(Sz[e[i].to]-t));
    	}
    	else//若y相对排名为3
    	{
    		ans+=1LL*(x-1-t1)*t1;//部分在子树外
    		for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&//完全在子树内
    			(t=S.Qry(e[i].to,1,x-1),res+=1LL*(t1-t)*t);
    	}ans+=res>>(p[2]!=2);
    }
    int main()
    {
    	RI Tt,i,x,y;F.read(Tt);W(Tt--)
    	{
    		for(F.read(n),S.Init(n),ee=0,i=1;i<=n;++i) lnk[i]=0;//清空
    		for(i=1;i<=3;++i) F.read(p[i]);for(i=1;i^n;++i) F.read(x,y),add(x,y),add(y,x);//读入建边
    		ans=0,dfs(1),printf("%lld
    ",ans);//输出答案
    	}return 0;
    }
    
  • 相关阅读:
    进程间多线程同步三种方法
    C++ 生成随机数 srand()和rand()
    事件对象用于多线程之间的同步
    $.ajax()方法参数详解
    面向对象的属性
    对多选框进行操作,输出选中的多选框的个数
    jQuery如何检查某个元素在网页上是否存在
    关于$.fn
    c#基础班笔记
    Sublime Text 3的快捷键
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CodeChef2019AugDiv2.html
Copyright © 2011-2022 走看看