• 【HHHOJ】NOIP2018 模拟赛(二十五) 解题报告


    点此进入比赛

    得分: (100+100+20=220)(T1)打了两个小时,以至于(T3)没时间打了,无奈交暴力)

    排名: (Rank 8)

    (Rating)(+19)

    (T1):【HHHOJ126】求和(点此看题面

    看到这道题,我不由得想到这道题目:【BZOJ1257】[CQOI2007] 余数之和

    于是就想到用除法分块去做。

    但是,由于记错了平方和公式(我毕竟还是太弱了... ...),结果打了两个小时... ...

    如果我们暂时把(i≠j)这个诡异的限制抛开不顾,则不难发现,((n\%i))这一项与(j)无关,((m\%j))这一项与(i)无关,所以我们可以把原式分成两部分:

    [sum_{i=1}^n(n\%i)*sum_{j=1}^m(m\%j) ]

    如果用(f(x))表示(sum_{i=1}^x(x\%i)),则原式就可以表示为:

    [f(n)·f(m) ]

    关于(f(n))怎么求,我想在【BZOJ1257】[CQOI2007] 余数之和这题的题解中我应该讲得很清楚了吧。

    但是,此时求得的答案包括了(i=j)的情况。

    所以我们要将(i=j)的答案从答案中减去。

    首先,不难发现,在(i=j)时的答案是长这样的(代入原式计算即可):

    [sum_{i=1}^{min(n,m)}(n\%i)(m\%i) ]

    依据对取模运算转化的常见套路,我们可以将其转化成这个样子:

    [sum_{i=1}^{min(n,m)}(n-lfloorfrac ni floor*i)(m-lfloorfrac mi floor*i) ]

    拆括号得:

    [sum_{i=1}^{min(n,m)}(nm-milfloorfrac ni floor-nilfloorfrac mi floor+i^2lfloorfrac ni floorlfloorfrac mi floor) ]

    这个式子显然是可以用除法分块来做的。

    于是就解决了呀。

    #include<bits/stdc++.h>
    #define LL long long
    #define ten(x) (((x)<<3)+((x)<<1))
    #define MOD 19940417
    #define min(x,y) ((x)<(y)?(x):(y))
    #define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
    #define Dec(x,y) ((x-=(y))<0&&(x+=MOD))
    #define f(x) ((((x)*((x)+1)>>1)%MOD)*((((x)<<1)+1)%MOD)%MOD*6646806%MOD)
    #define g(x,y) ((((x)+(y))*((y)-(x)+1)>>1)%MOD)
    using namespace std;
    LL n,m;
    class FIO
    {
    	private:
    		#define Fsize 100000
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (putchar(ch))
    		LL Top;char ch,*A,*B,Fin[Fsize],Stack[Fsize];
    	public:
    		FIO() {A=B=Fin;}
    		inline void read(LL &x) {x=0;while(!isdigit(ch=tc()));while(x=ten(x)+(ch&15),isdigit(ch=tc()));} 
    		inline void write(LL x)	{if(!x) return (void)(pc('0'));while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
    }F;
    inline LL Operate(LL x)//除法分块,类似于余数求和
    {
    	register LL l,r,res=x*x%MOD;
    	for(l=1;l<=x;l=r+1) r=x/(x/l),Dec(res,g(l,r)*(x/l)%MOD);
    	return res;
    }
    int main()
    {
    	register LL l,r,lim,ans;
    	F.read(n),F.read(m),ans=Operate(n)*Operate(m)%MOD;
    	for(l=1,Dec(ans,(lim=min(n,m))*n%MOD*m%MOD);l<=lim;l=r+1)//根据上面求出的式子,再一次除法分块,减去多余的答案 
    	{
    		r=min(n/(n/l),m/(m/l)),
    		Dec(ans,(f(r)-f(l-1))%MOD*(n/l)%MOD*(m/l)%MOD),
    		Inc(ans,g(l,r)*n%MOD*(m/l)%MOD),
    		Inc(ans,g(l,r)*m%MOD*(n/l)%MOD);
    	}
    	return F.write(ans),0; 
    }
    
    

    (T2):【HHHOJ127】排队(点此看题面

    这题没想到竟能在考试时间内做出来。

    快速幂写炸调了半个多小时祭。(深深感受到了自己的菜)

    首先,这种题目一看到,肯定先敲一个组合数板子

    然后就是乱搞((DFS)遍历(+)玄学转移),结果莫名其妙过了样例!

    更神奇的是,一交居然(A)了!

    其实这题也不是很难,就是组合数的一个应用,感觉还是挺好推的,这里就省略了。

    具体实现可以见代码:

    #include<bits/stdc++.h>
    #define ten(x) (((x)<<3)+((x)<<1))
    #define N 1000 
    #define MOD 10007
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    using namespace std;
    int n,ee=0,lnk[N+5];
    struct edge
    {
    	int to,nxt;
    }e[N+5];
    class FIO
    {
    	private:
    		#define Fsize 100000
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (putchar(ch))
    		int Top;char ch,*A,*B,Fin[Fsize],Stack[Fsize];
    	public:
    		FIO() {A=B=Fin;}
    		inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=ten(x)+(ch&15),isdigit(ch=tc()));}
    		inline void write(int x) {if(!x) return (void)(pc('0'));while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
    		inline void write_char(char x) {pc(x);}
    }F;
    class Class_Math//组合数
    {
    	private:
    		int Fac[N+5],Inv[N+5];
    		inline int quick_pow(int x,int y,register int res=1)//快速幂写炸调了半个多小时
    		{
    			for(;y;x=1LL*x*x%MOD,y>>=1) if(y&1) res=1LL*res*x%MOD;
    			return res;
    		}
    	public:
    		Class_Math()//预处理出阶乘和阶乘逆元
    		{
    			register int i;
    			for(Fac[0]=1,i=1;i<=N;++i) Fac[i]=Fac[i-1]*i%MOD;
    			for(Inv[N]=quick_pow(Fac[N],MOD-2),i=N-1;i>=0;--i) Inv[i]=Inv[i+1]*(i+1)%MOD;
    		}
    		inline int C(int x,int y) {return 1LL*Fac[x]*Inv[y]%MOD*Inv[x-y]%MOD;}//求组合数
    }Math;
    class Class_DfsSolver//DFS遍历
    {
    	private:
    		int ans[N+5],Size[N+5];//ans记录当前子树内的方案数,Size记录子树大小
    		inline void dfs(int x)
    		{
    			register int i;
    			for(ans[x]=1,Size[x]=0,i=lnk[x];i;i=e[i].nxt)//玄学转移
    				dfs(e[i].to),Size[x]+=Size[e[i].to],ans[x]=1LL*ans[x]*ans[e[i].to]%MOD*Math.C(Size[x]-1,Size[e[i].to]-1)%MOD;
    			++Size[x];
    		}
    	public:
    		inline void Solve() {dfs(1),F.write(ans[1]),F.write_char('
    ');}
    }DfsSolver;
    int main()
    {
    	register int i,x,y,T;F.read(T);
    	while(T--)
    	{
    		for(F.read(n),i=1,ee=0;i<=n;++i) lnk[i]=0;
    		for(i=1;i<=n;++i) for(F.read(x);x;--x) F.read(y),add(i,y);
    		DfsSolver.Solve();
    	}
    	return 0;
    }
    

    (T3):【HHHOJ128】城市(点此看题面

    原题: 【51nod1743】雪之国度

    由于(T1)打了两个多小时,结果虽然这题(Manchery)讲评过,但是没时间打了,直接交了暴力。

    其实这题实现起来真的要比想象中简单一些,题解可以参考上面的链接。

    代码如下:

    #include<bits/stdc++.h>
    #define ten(x) (((x)<<3)+((x)<<1))
    #define N 100000
    #define M 500000
    #define LogN 20
    #define INF 1000000000
    #define add(x,y,z) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].val=z)
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define abs(x) ((x)<0?-(x):(x)) 
    using namespace std;
    int n,m,ee=0,val[N+5],lnk[N+5];
    struct edge
    {
    	int from,to,nxt,val,vis;
    	inline friend bool operator < (edge x,edge y) {return x.val<y.val;}
    }s[M+5],e[(N<<1)+5];
    class FIO
    {
    	private:
    		#define Fsize 100000
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))
    		int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
    	public:
    		inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=ten(x)+(ch&15),isdigit(ch=tc()));}
    		inline void write(int x) {if(!x) return (void)(pc('0'));while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
    		inline void write_char(char x) {pc(x);}
    		inline void write_string(string x) {for(register int i=0,len=x.length();i<len;++i) pc(x[i]);}
    		inline void clear() {fwrite(Fout,1,FoutSize,stdout);}
    }F;
    class UnionFindSet
    {
    	public:
    		int fa[N+5];
    		inline void Clear() {for(register int i=1;i<=N;++i) fa[i]=i;}
    		UnionFindSet() {Clear();}
    		inline int getfa(int x) {return fa[x]^x?fa[x]=getfa(fa[x]):x;}
    		inline void Union(int x,int y) {if((x=getfa(x))^(y=getfa(y))) fa[y]=x;}
    }U;
    class Class_MulSolver
    {
    	public:
    		int Depth[N+5],fa[N+5][LogN+5],Max[N+5][LogN+5];
    	private:
    		inline void dfs(int x,int lst)
    		{
    			for(register int i=lnk[x];i;i=e[i].nxt)
    				if(e[i].to^lst) Depth[e[i].to]=Depth[fa[e[i].to][0]=x]+1,Max[e[i].to][0]=e[i].val,dfs(e[i].to,x);
    		}
    	public:
    		inline void DfsInit() {dfs(1,0);}
    		inline void MulInit() {for(register int i,j=1;j<=LogN;++j) for(i=1;i<=n;++i) fa[i][j]=fa[fa[i][j-1]][j-1],Max[i][j]=max(Max[i][j-1],Max[fa[i][j-1]][j-1]);}
    		inline int get_max(int x,int y)
    		{
    			if(Depth[x]<Depth[y]) swap(x,y);
    			register int i,res=0;
    			for(i=0;Depth[x]^Depth[y];++i) if((Depth[x]^Depth[y])&(1<<i)) res=max(res,Max[x][i]),x=fa[x][i];
    			if(!(x^y)) return res;
    			for(i=0;fa[x][i]^fa[y][i];++i);
    			for(--i;i>=0;--i) if(fa[x][i]^fa[y][i]) res=max(res,max(Max[x][i],Max[y][i])),x=fa[x][i],y=fa[y][i];
    			return max(res,max(Max[x][0],Max[y][0]));
    		}
    }MulSolver;
    int main()
    {
    	register int i,Q,x,y;
    	for(F.read(n),F.read(m),F.read(Q),i=1;i<=n;++i) F.read(val[i]);
    	for(i=1;i<=m;++i) F.read(s[i].from),F.read(s[i].to),s[i].val=abs(val[s[i].from]-val[s[i].to]);
    	for(sort(s+1,s+m+1),i=1;i<=m;++i) if(U.getfa(s[i].from)^U.getfa(s[i].to)) U.Union(s[i].from,s[i].to),s[i].vis=1,add(s[i].from,s[i].to,s[i].val),add(s[i].to,s[i].from,s[i].val);
    	for(U.Clear(),MulSolver.DfsInit(),i=1;i<=m;++i) 
    	{
    		if(s[i].vis) continue;
    		for(x=U.getfa(s[i].from),y=U.getfa(s[i].to);x^y;x=U.getfa(x))
    		{
    			if(MulSolver.Depth[x]<MulSolver.Depth[y]) swap(x,y);
    			MulSolver.Max[x][0]=s[i].val,U.fa[x]=MulSolver.fa[x][0];
    		}
    	}
    	for(MulSolver.MulInit();Q;--Q) F.read(x),F.read(y),(U.getfa(x)^U.getfa(y)?F.write_string("infinitely
    "):(F.write(MulSolver.get_max(x,y)),F.write_char('
    ')));
    	return F.clear(),0;
    }
    
  • 相关阅读:
    洛谷P2292 [HNOI2004]L语言
    洛谷P4052 [JSOI2007]文本生成器(AC自动机)
    洛谷P3193 [HNOI2008]GT考试(KMP,矩阵)
    创建目录命令
    ssh免密码登录机器(使用公钥和秘钥进行加密来实现)
    kafka工作原理介绍
    KafKa集群安装、配置
    Kafka的partions和replication-factor参数的理解
    linux之find命令详解
    将用户需求和新型技术输入,优质服务和价值体验输出。
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/HHHOJ_NOIP2018_25.html
Copyright © 2020-2023  润新知