zoukankan      html  css  js  c++  java
  • NOIP2018 集训(二)

    A题 神炎皇

    问题描述

    神炎皇乌利亚很喜欢数对,他想找到神奇的数对。

    对于一个整数对 ((a,b)) ,若满足 (a+bleq n)(a+b)(ab) 的因子,则称
    为神奇的数对。请问这样的数对共有多少呢?

    输入格式

    一行一个整数 (n)

    输出格式

    一行一个整数表示答案,保证不超过 (64) 位整数范围。

    数据范围与约定

    对于 (20\%) 的数据 (nleq 1000) ;

    对于 (40\%) 的数据 (nleq 10^5) ;

    对于 (60\%) 的数据 (nleq 10^7) ;

    对于 (80\%) 的数据 (n<=10^{12}) ;

    对于 (100\%) 的数据 (n<=10^{14})

    样例

    样例输入
    21
    样例输出
    4
    23

    题解

    首先暴力或者打表,都只能得20分

    //打表程序
    #include<bits/stdc++.h>
    using namespace std;
    inline char get(){
    	static char buf[30],*p1=buf,*p2=buf;
    	return p1==p2 && (p2=(p1=buf)+fread(buf,1,30,stdin),p1==p2)?EOF:*p1++;
    }
    inline long long read(){
    	register char c=get();register long long f=1,_=0;
    	while(c>'9' || c<'0')f=(c=='-')?-1:1,c=get();
    	while(c<='9' && c>='0')_=(_<<3)+(_<<1)+(c^48),c=get();
    	return _*f;
    }
    int main(){
    	freopen("watch.txt","w",stdout);
    	long long a,b;
    	long long n=0;
    	cout<<"a[]={0";
    	while(n<=10000005){
    		long long now=0;
    		n++;
    		for(register long long i=1;i<=n;i++){
    			for(register long long j=1;j<=n-i;j++){
    				//cout<<n<<":"<<i<<" "<<j<<endl;
    				if(i+j<=n && (i*j)%(i+j)==0){
    					//cout<<n<<":"<<i<<" "<<j<<endl;
    					now++;
    				}
    			}
    		}
    		cout<<","<<now;
    	}
    	cout<<"};";
    	return 0;
    }
    

    事实上,
    这个时候让我们来看一下数据范围,对于100%的数据$ nle10^{14} (,为什么是) 10 ^{14} $而不是(10^{18})呢?说明这个题要用一个复杂度为$ O(sqrt{n}) (的算法(程序1s通常可以运算) 10^{7} (次),于是乎我们再次对式子进行变形,尽量向)O(sqrt{n})(靠拢 先假设现在有满足条件的数)a,b(,同时我们设)d=gcd(a,b)(,则此时一定有:)(a^{'}=frac{a}{k} , b^{'}=frac{b}{k})$
    对式子进行变形,则可以得到:

    [k(a′+b′)\%k^2a′b′=0 ]

    (∵k(a′+b′)le n)
    $ ∴a'+b’ le sqrt{n}$

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int N=10000005;
    
    LL n,Ans;
    int m,f[N],p[N],phi[N];
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("uria.in","r",stdin);
    	freopen("uria.out","w",stdout);
    #endif
    	cin>>n;
    	int lim=int(sqrt(n)); 
    	for(int i=2;i<=lim;i++)
    	{
    		if(!f[i])
    			p[++m]=i,phi[i]=i-1;
    		for(int j=1;j<=m&&i*p[j]<=lim;j++)
    		{
    			f[i*p[j]]=1;
    			if(i%p[j]==0)
    			{
    				phi[i*p[j]]=phi[i]*p[j];break;
    			}
    			phi[i*p[j]]=phi[i]*(p[j]-1);
    		}
    		Ans+=n/i/i*phi[i];
    	}
    	cout<<Ans;
    	return 0;
    }
    

    ##B题 降雷神 #### 问题描述 降雷皇哈蒙很喜欢雷电,他想找到神奇的电光。

    哈蒙有 (n) 条导线排成一排,每条导线有一个电阻值,神奇的电光
    只能从一根导线传到电阻比它大的上面,而且必须从左边向右传导,
    当然导线不必是连续的。

    哈蒙想知道电光最多能通过多少条导线,还想知道这样的方案有
    多少。

    输入格式

    第一行两个整数 (n)(t)(t) 表示数据类型

    第二行 (n) 个整数表示电阻。

    输出格式

    第一行一个整数表示电光最多能通过多少条导线。

    如果 (t=1) 则需要输出第二行,表示方案数,对 (123456789) 取模。

    数据范围与约定

    对于 (20\%) 的数据 (nleq 10)

    对于 (40\%) 的数据 (nleq 1000)

    对于另外 (20\%) 的数据 (t=0)

    对于另外 (20\%) 的数据保证最多能通过不超过 (100) 条导线;

    对于 (100\%) 的数据 (nleq 100000) ,电阻值不超过 (100000)

    样例

    样例输入
    5 1
    1 3 2 5 4
    样例输出
    3
    4

    题解

    对于(t=0)的时候,直接求出最长上升子序列即可(二十分做法)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1000005;
    int n, a[maxn], f[maxn], g[maxn], ans;
    int t;
    int main() {
        cin >> n >> t;
        for (int i = 1; i <= n; i++) cin >> a[i];
    	memset(g,0x3f,sizeof(g));
        memset(f,0,sizeof(f));
        g[0]=0;
        ans=0;
        for(int i=1;i<=n;i++){
            f[i]=lower_bound(g+1,g+ans+1,a[i])-g;
            g[f[i]]=a[i];
            ans=max(ans,f[i]);
        }
        cout<<ans<<endl;
        return 0;
    }
    

    事实上,我们需要做的只是在求最长上升子序列的同时再求出方案数即可。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=100005,M=5000005,Mod=123456789;
    
    int lc[M],rc[M],s[M],rt[N],f[N],g[N],Max[N],Ans1,Ans2,tot,n,type;
    
    void Add(int& x,int l,int r,int p,int k)
    {
    	if(!x)
    		x=++tot,lc[x]=rc[x]=s[x]=0;
    	int Mid=l+r>>1;
    	s[x]=(s[x]+k)%Mod;
    	if(l==r)
    		return;
    	if(p<=Mid)
    		Add(lc[x],l,Mid,p,k);
    	else
    		Add(rc[x],Mid+1,r,p,k);
    }
    
    int Ask(int x,int l,int r,int p)
    {
    	if(r<=p)
    		return s[x];
    	int Mid=l+r>>1;
    	if(p<=Mid)
    		return Ask(lc[x],l,Mid,p);
    	return (s[lc[x]]+Ask(rc[x],Mid+1,r,p))%Mod;
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("hamon.in","r",stdin);
    	freopen("hamon.out","w",stdout);
    #endif
    	cin>>n>>type;
    	for(int i=1;i<=n;i++)
    	{
    		int a;scanf("%d",&a);
    		for(int j=a-1;j;j-=j&-j)
    			f[i]=max(f[i],Max[j]);
    		if(f[i]==0)
    			g[i]=1;
    		else
    			g[i]=Ask(rt[f[i]],0,N,a-1);
    		f[i]++;
    		if(f[i]>Ans1)
    			Ans1=f[i],Ans2=0;
    		if(f[i]==Ans1)
    			Ans2=(Ans2+g[i])%Mod;
    		Add(rt[f[i]],0,N,a,g[i]);
    		for(int j=a;j<N;j+=j&-j)
    			Max[j]=max(Max[j],f[i]);
    	}
    	cout<<Ans1<<endl;
    	if(type)
    		cout<<Ans2<<endl;
    	return 0;
    }//来自十里坡键神
    
  • 相关阅读:
    TOC 1. TODO springboot优雅关机
    SpringBoot实现优雅的关机
    Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现
    正确、安全地停止SpringBoot应用服务
    springboot优雅关机
    简单几步教你实现移动硬盘PE、装win7/vista! 一盘在手,系统无忧!
    设置vista和win7进入Debug模式
    杀毒绝招:用“记事本” 处理顽固程序(命令行修改默认打开方式)
    win7 UAC bypass(微软已经给予了三组组件绕过UAC启动的特权)
    Win7,Vista UAC下应用程序标注为“需要管理员权限”的四种方法(可以修改注册表)
  • 原文地址:https://www.cnblogs.com/Chen574118090/p/9809926.html
Copyright © 2011-2022 走看看