zoukankan      html  css  js  c++  java
  • [正睿集训2021] 模拟赛4

    整数对

    题目描述

    求满足 (0leq xleq n,0leq yleqsqrt{frac{p}{q}}cdot x)((x,y)) 的整数对个数。

    (1leq Tleq 10^5,1leq p,qleq 1000,1leq nleq 10^9)

    解法

    太棒啦,一道题掌握两个高科技。

    这个 (sqrt{frac{p}{q}}) 有点烦,我们用 Stern-Brocot树 来把这个东西拟合成有理数 (frac{a}{b}),我的方式是如果拟合出来的有理数要爆出 (1e17) 了那么我们退出拟合,我们再限定一个拟合次数 (5000),如果超过这个次数我们就认为精度够了。

    剩下的问题变成了求 (sum_{x=0}^nlfloorfrac{ax}{b} floor),直接搞个类欧几里得就行了。

    #include <cstdio>
    #include <cmath>
    #define int __int128
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    void write(int x)
    {
    	if(x<0) x=-x,putchar('-');
    	if(x>9) write(x/10);
    	putchar(x%10+'0');
    }
    int T,p,q,n,t;
    int work(int n,int a,int b,int c)
    {
    	int ac=a/c,bc=b/c,n1=n+1,m=(a*n+b)/c,f=0;
    	if(!a) return bc*n1;
    	if(a>=c || b>=c)
    	{
    		f=n*n1/2*ac+n1*bc+work(n,a%c,b%c,c);
    		return f;
    	}
    	f=n*m-work(m-1,c,c-b-1,a);
    	return f;
    }
    void find(int a,int b,int c,int d)
    {
    	t++;
    	if(c>=1e17 || d>=1e17 || t>=5000)
    	{
    		write(work(n,a,0,b)+n+1);
    		puts("");
    		return ;
    	}
    	int m=a+c,n=b+d;
    	if(n*n*p<m*m*q) find(a,b,m,n);
    	else find(m,n,c,d); 
    }
    signed main()
    {
    	T=read();
    	while(T--)
    	{
    		t=0;
    		p=read();q=read();n=read();
    		find(0,1,1,0);
    	}
    }
    

    序列变换

    题目描述

    对于一个长度为 (n),下标为 ([0,n)) 的非负整数序列 (a),定义变换 (b=f(a,k)),其中 (b) 也是长度为 (n) 的序列,且 (b_i=oplus_{j=0}^{k-1}a_{(i+j)mod n}),问变换 (T) 次之后得到的序列。

    (1leq kleq nleq5cdot 10^5,1leq Tleq 10^{18})

    解法

    这道题变换其实有点复杂,算贡献这个方法是行不通的。

    不妨从卷积的角度来理解这个变换,定义乘法为异或起来的卷积,设初始序列的生成函数是 (F(x)),则有:

    [F(x) imes (1+x...+x^{k-1})^Tmod (x^n-1) ]

    后面的部分可以暴力卷起来,相当于是在模 (2) 意义下的卷积,但是 (O(nlog klog n)) 直接 ( t T) 飞了。

    有一个神奇结论:((1+x...+x^{k-1})^{2^t}=1+x^{2^t}...+x^{(k-1)2^t}),这个可以归纳证明,不是自己乘自己的项的系数都是 (2) 的倍数,所以都被模掉了,然后一直归纳上来即可。

    (F(x) imes(1+x...+x^{k-1})^Tmod(x^n-1)) 是可以 (O(n)) 算的,就把每一类的东西取出来,然后做一个类似前缀和的东西就行了,讨论一下 (k) 大于整类的情况,所以直接二进制拆分 (O(nlog T))

    #include <cstdio>
    #include <vector>
    using namespace std;
    #define int long long
    const int M = 500005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,k,t,a[M],b[M],vis[M];vector<int> v;
    void work(int x)
    {
    	for(int i=0;i<n;i++)
    	{
    		v.clear();
    		if(!vis[i])
    		{
    			//取出这一类所有的元素
    			int ans=0;
    			for(int j=i;!vis[j];j=(j+x)%n)
    				vis[j]=1,v.push_back(j),ans^=a[j];
    			if((k/v.size())%2==0) ans=0;//否则可以取遍整类 
    			int u=k%v.size();
    			for(int j=0;j<u;j++)
    				ans^=a[v[j]];
    			for(int j=0;j<v.size();j++)
    			{
    				b[v[j]]=ans;
    				ans^=a[v[j]];
    				ans^=a[v[(j+u)%v.size()]];
    			}
    		}
    	}
    	for(int i=0;i<n;i++) a[i]=b[i],b[i]=vis[i]=0;
    }
    signed main()
    {
    	n=read();k=read();t=read();
    	for(int i=0;i<n;i++)
    		a[i]=read();
    	for(int p=1;t;p<<=1)
    		if(t&p)
    		{
    			t^=p;
    			work(p%n);
    		}
    	for(int i=0;i<n;i++) printf("%d ",a[i]);
    }
    
  • 相关阅读:
    jsp的C标签一般使用方法以及js接收servlet中的对象及对象数字
    关于Springmvc中include与Sitemesh装饰器的基本使用
    关于垃圾回收的一些基本原理及技术解析
    一张图解析 编译器编译流程
    Java解析OFFICE(word,excel,powerpoint)以及PDF的实现方案及开发中的点滴分享
    冲刺五
    冲刺四
    冲刺三
    冲刺二
    冲刺一
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14590203.html
Copyright © 2011-2022 走看看