• jQuery火箭图标返回顶部代码


    T1:a

    【题目描述】

    对于给定的一个正整数(n), 判断n是否能分成若干个正整数之和 (可以重复) ,其中每个正整数都能表示成两个质数乘积。

    【输入描述】

    第一行一个正整数 (q),表示询问组数。
    接下来 (q) 行,每行一个正整数 (n),表示询问。

    【输出描述】

    (q) 行,每行一个正整数,为$ 0$ 或 (1)(0) 表示不能,(1) 表示能。

    【输入样例】

    (5)
    (1)
    (4)
    (5)
    (21)
    (25)

    【输出样例】

    (0)
    (1)
    (0)
    (1)
    (1)

    【样例解释】

    (4=2*2)
    (21=6+15=2*3+3*5)
    (25=6+9+10=2*3+3*3+2*5)
    (25=4+4+4+4+9=2*2+2*2+2*2+2*2+3*3)

    【数据范围】

    (30\%)的数据满足:(qleq 20,nleq 20)
    (60\%)的数据满足:(qleq 10000,nleq 5000)
    (100\%)的数据满足:(qleq 10^5,nleq 10^{18})

    Solution

    (n leq 20) 时,只有(1,2,3,5,7,11)无解,其余均有解。
    (n > 20) 时,因为(n = (n-4) + 4 = (n-4) + 2 * 2),而((n-4))这个数(geq 16),是一定有解的。
    所以,我们证明了对于任意的正整数(n),
    只有(n = 1,2,3,5,7,11)时无解,其余均有解。
    那么我们只需要在每组数据中判断一下n是否等于(1,2,3,5,7,11)中的任意一个即可。
    复杂度(O(q)).

    Code
    //****定理 
    #include <cstdio>
    #include <iostream>
    using namespace std;
    int q;
    long long x;
    long long read() {
    	long long s = 0, w = 1;
    	char ch = getchar();
    	while(!isdigit(ch)) {if(ch == '-') w = -1;ch = getchar();}
    	while(isdigit(ch)) {s = s * 10 + ch - '0';ch = getchar();}
    	return s * w; 
    }
    int pd(int x) {
    	if(x == 4) return 1;
    	if(x == 6) return 1;
    	if(x == 8) return 1;
    	if(x == 9) return 1;
    	if(x == 10) return 1;
    	if(x == 12) return 1;
    	return 0;
    }
    int main() {
    	freopen("a.in", "r", stdin);
    	freopen("a.out", "w", stdout);
    	q = read();
    	while(q--) {
    		x = read();
    		if(x <= 12) 
    			if(pd(x)) printf("1
    ");
    			else printf("0
    ");
    		else printf("1
    ");
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
     
    

    T2:b

    【题目描述】

    有一个长度为(n)的自然数序列(a),要求将这个序列恰好分成至少(m) 个连续子段。 每个子段的价值为该子段的所有数的按位异或。要使所有子段的价值按位与的结果最大,输出这个最大值。

    【输入描述】

    第一行一个正整数 (q),表示询问组数。
    接下来$ q$ 组输入,每组输入两行:
    第一行两个正整数 (n,m)
    第二行 $n $个正整数,描述序列 (a)

    【输出描述】

    一行一个正整数,表示答案。

    【输入样例】

    (1)
    (5) (3)
    (1) (2) (3) (4) (5)

    【输出样例】

    (1)

    【数据范围】

    (20\%)的数据:(nleq 20)
    (40\%)的数据:(nleq 100,a_i<256)
    (60\%)的数据:(nleq 100)
    (100\%)的数据:(1leq qleq 12,1leq mleq nleq 1000,0leq a_i<2^{30})

    Solution

    因为异或运算具有交换律且((x)异或(x = 0)),所以区间异或和可以由两个前缀异或和异或得到。
    考虑从高位到低位确定答案的二进制位,然后考虑判断是否能分成至少(m)段。
    如何判断是否能分成至少(m)段?
    "能分成至少(m)段"与"最多能分成的段数(geq m)"等价。
    (dp[i] = a[1..i])这一段数最多能分成多少段"
    转移就是直接枚举上一段的末尾j,如果([j+1,i])可以组成一段,那么就把(dp[i] = max(dp[i],dp[j] + 1));
    这样(DP)的复杂度是(O(n^2))
    总复杂度就是(O(q * log(值域) * DP) = O(30qn^2) approx 3.6 * 10^8),因为常数较小可以过。

    值得一提的是,直接(O(N^3)DP)是错误的。因为它不满足最优子结构。
    Code

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    int q,n,m,ans,x,s[1005],f[1005];
    
    int rd(){
    	int re=0,f=1;char c=getchar();
    	while ((c<'0')||(c>'9')) {if (c=='-') f=-f;c=getchar();}
    	while ((c>='0')&&(c<='9')) {re=re*10+c-'0';c=getchar();}
    	return re*f;
    }
    
    int Max(int x,int y){
    	return ((x>y)?x:y);
    }
    
    int main(){
    	freopen("b.in","r",stdin);
    	freopen("b.out","w",stdout);
    	q=rd();
    	for (;q>0;--q){
    		n=rd();m=rd();
    		s[0]=0;
    		for (int i=1;i<=n;++i){
    			x=rd();s[i]=s[i-1]^x;
    		}
    		
    		ans=0;
    		for (int i=29;i>=0;--i){
    			memset(f,0,sizeof(f));
    			f[0]=1;
    			for (int j=1;j<=n;++j){
    				for (int k=0;k<j;++k) if (f[k]>0){
    					x=s[j]^s[k];
    					if (((ans&x)>=ans)&&((x&(1<<i))>0))
    						f[j]=Max(f[k]+1,f[j]);
    				}
    			}
    			if (f[n]>m) ans|=(1<<i);
    		}
    		
    		cout<<ans<<'
    ';
    	}
    	return 0;
    }
    

    T3:c

    【题目描述】

    定义一个排列 (a) 的价值为满足(|a[i]-i|leq 1)(i)的数量。
    给出三个正整数 (n,m,p),求出长度为$ n $且价值恰好为 (m) 的排列的个数对 (p)
    模的结果。

    【输入描述】

    第一行两个正整数 (T,p),$T (为数据组数,)p $为模数。
    接下来 (T) 行,每行两个正整数 (n,m)

    【输出描述】

    $T $行,每行一个非负数,表示答案。

    【输入样例】

    (5) (1887415157)
    (3) (1)
    (3) (2)
    (3) (3)
    (50) (10)
    (1500) (200)

    【输出样例】

    (1)
    (2)
    (3)
    (621655247)
    (825984474)

    【数据范围】

    (10\%)的数据:(nleq 10)
    (30\%)的数据:(nleq 15)
    (50\%)的数据:(nleq 200)
    另有 (10\%)的数据:(m=1)
    另有$ 10%(的数据:)m=n-1$
    (100\%)的数据:(1leq T,n,mleq 2000,2leq pleq 10^{12})

    Solution:

    题解:
    因为(n,m leq 2000),而且(p)是事先给出的,所以我们可以一次性预处理出(n,mleq 2000)的答案。

    考虑一个长度为(i)的排列如何变成长度为(i+1)的排列。
    一种情况是我在它末尾加入了一个数(i+1),另一种情况是我用(i+1)替换掉了原来排列中的一个数,然后把被换掉的数放到排列的末尾。
    那么,这个排列权值的变化就是:
    第一种情况:在它末尾加入了一个数(i+1),权值(+1)
    第二种情况:用(i+1)替换掉一个数,权值 (+=) 加的贡献$ -$ 换掉的数的贡献。

    (DP)当中,我们只需要考虑替换掉的数是否是(i),以及(i)是否在位置(frac{i}{i-1})即可。总共有(5)种本质不同的状态,分类讨论转移即可。
    复杂度(O(nm))

    Code:
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    const int N=2005;
    
    int q,n,m,u,v;
    LL p,ans,f[N][N][5],x;
    
    int rd(){
    	int re=0,f=1;char c=getchar();
    	while ((c<'0')||(c>'9')) {if (c=='-') f=-f;c=getchar();}
    	while ((c>='0')&&(c<='9')) {re=re*10+c-'0';c=getchar();}
    	return re*f;
    }
    
    int main(){
    	freopen("c.in","r",stdin);
    	freopen("c.out","w",stdout);
    	cin>>q>>p;
    	memset(f,0,sizeof(f));
    	f[1][1][0]=1ll;
    	f[2][2][0]=1ll;f[2][2][1]=1ll;
    	
    	n=2000;
    	for (int i=2;i<n;++i)
    		for (int j=0;j<=n;++j){
    			for (int k=0;k<=4;++k){
    				x=f[i+1][j+1][0]+f[i][j][k];
    				x=(x<p)?x:(x-p);
    				f[i+1][j+1][0]=x;
    				u=j+((k%2)==0);
    				v=1+(k!=0);
    				x=f[i+1][u][v]+f[i][j][k];
    				x=(x<p)?x:(x-p);
    				f[i+1][u][v]=x;
    			}
    			
    			if (f[i][j][0]>0ll){
    				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][0]*(LL)(j-1))%p;
    				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][0]*(LL)(i-j))%p;
    			}
    			if (f[i][j][1]>0ll){
    				x=f[i+1][j][3]+f[i][j][1];
    				x=(x<p)?x:(x-p);
    				f[i+1][j][3]=x;
    				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][1]*(LL)(j-2))%p;
    				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][1]*(LL)(i-j))%p;
    			}
    			if (f[i][j][2]>0ll){
    				x=f[i+1][j][3]+f[i][j][2];
    				x=(x<p)?x:(x-p);
    				f[i+1][j][3]=x;
    				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][2]*(LL)(j-1))%p;
    				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][2]*(LL)(i-j-1))%p;				
    			}
    			if (f[i][j][3]>0ll){
    				x=f[i+1][j+1][3]+f[i][j][3];
    				x=(x<p)?x:(x-p);
    				f[i+1][j+1][3]=x;
    				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][3]*(LL)(j-1))%p;
    				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][3]*(LL)(i-j-1))%p;	
    			}
    			if (f[i][j][4]>0ll){
    				x=f[i+1][j+1][3]+f[i][j][4];
    				x=(x<p)?x:(x-p);
    				f[i+1][j+1][3]=x;		
    				if (j>0) f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][4]*(LL)(j))%p;
    				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][4]*(LL)(i-j-2))%p;	
    			}
    		}
    	
    	for (;q>0;--q){
    		cin>>n>>m;
    		ans=(f[n][m][0]+f[n][m][1]+f[n][m][2]+f[n][m][3]+f[n][m][4])%p;
    		cout<<ans<<'
    ';
    	}
    	return 0;
    }
    

    谢谢收看,祝身体健康!

  • 相关阅读:
    JavaScript:Number 对象
    JavaScript:Math 对象
    杂项:引用资源列表
    小团队管理与大团队管理
    技术转管理
    【翻译+整理】.NET Core的介绍
    自己开发给自己用的个人知识管理工具【脑细胞】,源码提供
    关于【自证清白】
    这篇博客能让你戒烟——用程序员的思维来戒烟!
    如果我是博客园的产品经理【下】
  • 原文地址:https://www.cnblogs.com/yanxiujie/p/11685514.html
Copyright © 2020-2023  润新知