zoukankan      html  css  js  c++  java
  • 2019年我能变强组队训练赛第一场

    Array Without Local Maximums

    #include <bits/stdc++.h>
     
    using namespace std;
    typedef long long ll;
    const int maxn=100001;
    const ll mod=998244353;
    int n,a[maxn];
    ll f[maxn][201][3],sum,ans;
    int main()
    {
        scanf("%d",&n);
        for (int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
        }
        for (int i=1; i<=200; i++)
        {
            if (a[1]!=-1&&a[1]!=i)
            {
                f[1][i][0]=f[1][i][1]=f[1][i][2]=0;
            }
            else
            {
                f[1][i][0]=1;
                f[1][i][1]=0;
                f[1][i][2]=0;
            }
        }
        for (int i=2; i<=n; i++)
        {
            sum=0;
            for (int j=1; j<=200; j++)
            {
                if (a[i]!=-1&&a[i]!=j)
                {
                    f[i][j][0]=0;
                }
                else
                {
                    f[i][j][0]=sum;
                }
                sum=(sum+f[i-1][j][0]+f[i-1][j][1]+f[i-1][j][2])%mod;
            }
            for (int j=1; j<=200; j++)
            {
                if (a[i]!=-1&&a[i]!=j)
                {
                    f[i][j][1]=0;
                }
                else
                {
                    f[i][j][1]=(f[i-1][j][0]+f[i-1][j][1]+f[i-1][j][2])%mod;;
                }
            }
            sum=0;
            for (int j=200; j>=1; j--)
            {
                if (a[i]!=-1&&a[i]!=j)
                {
                    f[i][j][2]=0;
                }
                else
                {
                    f[i][j][2]=sum;
                }
                sum=(sum+f[i-1][j][1]+f[i-1][j][2])%mod;
            }
        }
        for (int i=1; i<=200; i++)
        {
            ans=(ans+f[n][i][2]+f[n][i][1])%mod;
        }
        printf("%lld
    ",ans);
    }

    Shell Pyramid

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll i,j,k,n;
      
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%lld",&n) ;
            i = (ll)(pow(double(n) * 6.0,1.0/3.0))-1;
            while(i*(i+1)/2*(i+2)/3 < n )
            {
                i ++ ;
            }
            n -= (i-1)*(i)/2*(i+1)/3 ;
            j = (ll)(sqrt(n * 2.0)) ;
            while(j * (j+1)/2 < n)
                j ++ ;
            n -=j*(j-1)/2 ;
            k= n;
            printf("%lld %lld %lld
    ",i,j,k) ;
        }
        return 0;
    }
    

    Gauss Elimination

    import java.util.*;
    import java.math.*;
     
    public class Main
    {
        public static BigInteger g[][] = new BigInteger[110][110];
     
        public static boolean Gauss_Elimination(int n)
        {
            BigInteger tmp,a,b;
            int i,j,k;
            for (i=0; i<n; i++)
            {
                for (j=i; j<n; j++)
                {
                    if (g[j][i].compareTo(BigInteger.ZERO)!=0)
                    {
                        break;
                    }
                }
                if (j>=n)
                {
                    return false;
                }
                if (i!=j)
                {
                    for (k=0; k<=n; k++)
                    {
                        tmp=g[i][k];
                        g[i][k]=g[j][k];
                        g[j][k]=tmp;
                    }
                }
                a=g[i][i];
                for (j=i+1; j<n; j++)
                {
                    if (g[j][i].compareTo(BigInteger.ZERO)!=0)
                    {
                        b=g[j][i];
                        for (k=i; k<=n; k++)
                        {
                            g[j][k]=g[j][k].multiply(a).subtract(g[i][k].multiply(b));
                        }
                    }
                }
            }
            return true;
        }
        public static void main (String[] args)
        {
            Scanner cin = new Scanner(System.in);
            BigInteger x[]= new BigInteger[110];
            BigInteger y[]= new BigInteger[110];
     
            BigInteger tmp,up,down;
     
            int n,i,j;
     
            boolean neg;
     
            while (cin.hasNext())
            {
                n=cin.nextInt();
                for (i=0; i<n; i++)
                {
                    for (j=0; j<=n; j++)
                    {
                        g[i][j]=cin.nextBigInteger();
                    }
                }
                if (Gauss_Elimination(n))
                {
                    for (i=n-1; i>=0; i--)
                    {
                        up=BigInteger.ZERO;
                        down=BigInteger.ONE;
                        for (j=i+1; j<n; j++)
                        {
                            up=y[j].multiply(up).add(g[i][j].multiply(x[j].multiply(down)));
                            down=y[j].multiply(down);
                        }
                        up=g[i][n].multiply(down).subtract(up);
                        down=g[i][i].multiply(down);
                        if (up.multiply(down).compareTo(BigInteger.ZERO)<0)
                        {
                            neg=true;
                        }
                        else
                        {
                            neg=false;
                        }
                        up=up.abs();
                        down=down.abs();
                        tmp=up.gcd(down);
                        x[i]=up.divide(tmp);
                        y[i]=down.divide(tmp);
                        if (neg)
                        {
                            x[i]=x[i].negate();
                        }
                    }
                    for (i=0; i<n; i++)
                    {
                        if (x[i].mod(y[i]).compareTo(BigInteger.ZERO)==0)
                        {
                            System.out.println(x[i].divide(y[i]));
                        }
                        else
                        {
                            System.out.println(x[i]+"/"+y[i]);
                        }
                    }
                }
                else
                {
                    System.out.println("No solution.");
                }
                System.out.println();
            }
        }
    }
    

    Simple Addition expression

    题意:给出数n,在区间[0,n]中取值i,使得 (i) + (i+1) + (i+2), i>=0间的计算不会产生进位

    统计在小于n的情况下,有多少个i符合i+i+1+i+2没有进位
    首先因为没有进位,那么能够确定除了个位之外所有是0~3
    而个位因为加了3,那么个位仅仅能是0~2

    然后又研究了好一会才知道什么解,个位数不能超过2,其他位数不超过3即可:即个位最大为3,其他位最大为4.把这个数当做字符串就好解决了,从这个字符串的第一位开始判断就可以了……然后计算这些排列数就行了。如果为个数,就直接加上,如果有其他位数,那先判断第一位,如果大于3就可以直接用相乘,如果小于3的话,那这位数之前的可以直接相乘,这位数的情况就往下位数继续判断……这样依次判断到最后个位数就行了……把这些结果相加就得到结果了。

    #include<bits/stdc++.h>
    
    using namespace std;
    char a[100];
    typedef long long ll;
    ll sum,c;
    int main()
    {
        while (~scanf("%s",a))
        {
            sum=0;
            int len=strlen(a);
            for (int i=0; i<len; i++)
            {
                c=a[i]-'0';
                if (i==len-1)
                {
                    if (c<3)
                    {
                        sum+=c;
                    }
                    else
                    {
                        sum+=3;
                    }
                    break;
                }
                if (c<4)
                {
                    sum+=c*pow(4,len-i-2)*3;
                }
                else
                {
                    sum+=pow(4,len-i-1)*3;
                    break;
                }
            }
            printf("%lld
    ",sum);
        }
    }

    Degree Sequence of Graph G

    #include<bits/stdc++.h>
    
    using namespace std;
    priority_queue<int>q;
    int a[100000],n,x,f;
    int main(){
        int T;
        scanf("%d",&T);
        while (T--){
            f=0;
            while (!q.empty()){
                q.pop();
            }
            scanf("%d",&n);
            for (int i=1;i<=n;i++){
                scanf("%d",&x);
                if (x) q.push(x);
            }
            while (!q.empty()){
                x=q.top();
                q.pop();
                if (x>q.size()){
                    f=1;
                    break;
                }
                for (int i=1;i<=x;i++){
                    a[i]=q.top()-1;
                    q.pop();
                }
                for (int i=1;i<=x;i++){
                    if (a[i]){
                        q.push(a[i]);
                    }
                }
            }
            if (f){
                printf("no
    ");
            }else{
                printf("yes
    ");
            }
        }
    }

    Navy maneuvers

    #include<bits/stdc++.h>
    
    using namespace std;
    const int maxn=10010;
    int f[10010][2],in[maxn],w[maxn],m,n,ff;
    vector<int>E[maxn];
    int dfs(int cur,int turn){
        if (f[cur][turn&1]!=-1){
            return f[cur][turn&1];
        }
        if (E[cur].size()==0){
            return f[cur][turn&1]=w[cur];
        }
        f[cur][turn&1]=0;
        int len=E[cur].size(),mn=0x3f3f3f3f,mx=-0x3f3f3f3f;
        for (int i=0;i<len;i++){
            int to = E[cur][i];
            if (turn&1){
                mx=max(mx,dfs(to,turn+1));
            }else{
            mn=min(mn,dfs(to,turn+1));
            }
        }
        if (turn&1){
            return f[cur][turn&1]=w[cur]+mx;
        }else{
            return f[cur][turn&1]=w[cur]+mn;
        }
    }
    int main()
    {
        while (~scanf("%d%d%d",&n,&m,&ff))
        {
            memset(f,-1,sizeof (f));
            for (int i=1; i<=n; i++)
            {
                in[i]=0;
                E[i].clear();
            }
            int ans=0;
            for (int i=1; i<=n; i++)
            {
                scanf("%d",&w[i]);
            }
            for (int i=1,u,v; i<=m; i++)
            {
                scanf("%d%d",&u,&v);
                E[u].push_back(v);
                in[v]++;
            }
            for (int i=1; i<=n; i++)
            {
                if (!in[i])
                {
                    ans=max(ans,dfs(i,1));
                }
            }
            if (ans>=ff)
            {
                puts("Victory");
            }
            else
            {
                puts("Glory");
            }
        }
        return 0;
    }

    Mining Station on the Sea

    给你n个船和n个港口,m个采矿点,k条矿点之间的边,p条港口和矿井的边。问n条船与n个港口一一匹配的最小路程。将路程转化为费用,用最小费用流模型求解。
    设矿点的编号为1 ~ m,港口的编号m + 1 ~ m + n
    对所有的船 i 和起点建边(s,i, 1, 0);
    对所有的港口 x 和终点建边(x + m, t, 1, 0);
    对有路的矿点 u 和矿点 v建边(u,v,oo,w),(v,u,oo,w),因为路可以重复走,所以容量设为oo;
    最后对有路的矿点 u 和港口 v 建边(v,u + m,1,w)。

    建图如下:

    ①建立源点S,将其连入各个船所在的点,权值设定为1,费用设定为0,表示只有一个船.

    ②建立汇点T,将各个港口连入汇点T,权值设定为1,费用设定为0,表示只能停一个船.

    ③将m条无向边直接建立起来,权值设定为其距离,费用设定为INF。表示可以走无数次。

    ④将p条有向边直接建立起来,将点连入港口,权值设定为其距离,费用设定为1。

    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxm=2000000;
    const int maxn=330;
    const int inf=0x3f3f3f3f;
    typedef pair<int,int> PI;
    struct MCFC {
        struct edge {
            int to, next, cap, flow, cost;
        } e[maxm];
        int head[maxn], tol;
        int pre[maxn], dis[maxn];
        bool vis[maxn];
        int N;
    
        void init(int n) {
            N = n;
            tol = 1;
            memset(head, 0, sizeof(head));
        }
    
        void addedge(int u, int v, int cap, int cost) {
            tol++;
            e[tol].to = v;
            e[tol].cap = cap;
            e[tol].cost = cost;
            e[tol].flow = 0;
            e[tol].next = head[u];
            head[u] = tol;
            tol++;
            e[tol].to = u;
            e[tol].cap = 0;
            e[tol].flow = 0;
            e[tol].cost = -cost;
            e[tol].next = head[v];
            head[v] = tol;
        }
    
        bool spfa(int s, int t) {
            queue<int> q;
            for (int i = 0; i <= N; i++) {
                dis[i] = inf;
                vis[i] = false;
                pre[i] = -1;
            }
            dis[s] = 0;
            vis[s] = true;
            q.push(s);
            while (!q.empty()) {
                int u = q.front();
                q.pop();
                vis[u] = false;
                for (int i = head[u]; i; i = e[i].next) {
                    int v = e[i].to;
                    if (e[i].cap > e[i].flow && dis[v] >dis[u] + e[i].cost) {
                        dis[v] = dis[u] + e[i].cost;
                        pre[v] = i;
                        if (!vis[v]) {
                            vis[v] = true;
                            q.push(v);
                        }
                    }
                }
            }
            if (pre[t] == -1) return false;
            else return true;
        }
    
        int cost = 0;
    
        PI mcmf(int s, int t) {
            int flow = 0;
            cost = 0;
            while (spfa(s, t)) {
                int minn = inf;
                for (int i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) {
                    if (minn > e[i].cap - e[i].flow) {
                        minn = e[i].cap - e[i].flow;
                    }
                }
                for (int i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) {
                    e[i].flow += minn;
                    e[i ^ 1].flow -= minn;
                    cost += e[i].cost * minn;
                }
                flow += minn;
            }
            return make_pair(cost,flow);
        }
    
    } G;
    
    int main(){
        int n,m,k,p,T,S,pos,u,v,w;
        while (~scanf("%d%d%d%d",&n,&m,&k,&p)){
            T=n+m+1;
            S=0;
            G.init(T);
            for (int i=1;i<=n;i++){
                scanf("%d",&pos);
                G.addedge(S,pos,1,0);
            }
            for (int i=1;i<=n;i++){
                G.addedge(m+i,T,1,0);
            }
            for (int i=1;i<=k;i++){
                scanf("%d%d%d",&u,&v,&w);
                G.addedge(u,v,inf,w);
                G.addedge(v,u,inf,w);
            }
            for (int i=1;i<=p;i++){
                scanf("%d%d%d",&u,&v,&w);
                G.addedge(v,u+m,1,w);
            }
            printf("%d
    ",G.mcmf(S,T).first);
        }
    }
    
    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxm=900000;
    const int maxn=330;
    const int inf=0x3f3f3f3f;
    typedef pair<int,int> PI;
    
    struct Min_Cost_Max_Flow{
        struct edge{
            int to,cap,cost,rev;
            edge(){};
            edge(int _to,int _cap,int _cost,int _rev):to(_to),cap(_cap),cost(_cost),rev(_rev){};
        };
        vector<edge>E[maxm];
        int h[maxn],n,d[maxn],preV[maxn],preE[maxn];
        void init(int n){
            this->n=n;
            for (int i=0;i<=n;i++){
                E[i].clear();
                h[i]=0;
            }
        }
        void add(int from,int to,int cap,int cost){
            E[from].push_back(edge(to,cap,cost,E[to].size()));
            E[to].push_back(edge(from,0,-cost,E[from].size()-1));
        }
    
        PI dijkstra(int s,int t,int f){
            int cost=0,flow=0;
            for (int i=0;i<=n;i++){
                h[i]=0;
            }
            while (f){
                priority_queue<PI,vector<PI>,greater<PI> >q;
                for (int i=0;i<=n;i++){
                    d[i]=inf;
                }
                d[s]=0;
                q.push(make_pair(0,s));
                while (!q.empty()){
                    PI now=q.top();
                    q.pop();
                    int v=now.second;
                    if (d[v]<now.first){
                        continue;
                    }
                    for (int i=0;i<E[v].size();i++){
                        edge &e=E[v][i];
                        if (e.cap>0&&d[e.to]>d[v]+e.cost+h[v]-h[e.to]){
                            d[e.to]=d[v]+e.cost+h[v]-h[e.to];
                            preV[e.to]=v;
                            preE[e.to]=i;
                            q.push(make_pair(d[e.to],e.to));
                        }
                    }
                }
                if (d[t]==inf)break;
                for (int i=0;i<=n;i++){
                    h[i]+=d[i];
                }
                int d=f;
                for (int i=t;i!=s;i=preV[i]){
                    d=min(d,E[preV[i]][preE[i]].cap);
                }
                f-=d;
                flow+=d;
                cost+=d*h[t];
                for (int i=t;i!=s;i=preV[i]){
                        edge &e=E[preV[i]][preE[i]];
                        e.cap-=d;
                        E[i][e.rev].cap+=d;
                }
            }
            return make_pair(flow,cost);
        }
    }G;
    
    int main(){
        int n,m,k,p,T,S,pos,u,v,w;
        while (~scanf("%d%d%d%d",&n,&m,&k,&p)){
            T=n+m+1;
            S=0;
            G.init(T);
            for (int i=1;i<=n;i++){
                scanf("%d",&pos);
                G.add(S,pos,1,0);
            }
            for (int i=1;i<=n;i++){
                G.add(m+i,T,1,0);
            }
            for (int i=1;i<=k;i++){
                scanf("%d%d%d",&u,&v,&w);
                G.add(u,v,inf,w);
                G.add(v,u,inf,w);
            }
            for (int i=1;i<=p;i++){
                scanf("%d%d%d",&u,&v,&w);
                G.add(v,u+m,1,w);
            }
            printf("%d
    ",G.dijkstra(S,T,inf).second);
        }
    }
    

    Carrying Out A Task

    简述一下题意:

    20*20的地图上,一个起点S,一个终点E,障碍物#,漩涡*

    一艘船从起点出发,携带充足的A类油和X升B类油。

    沿上下左右四个方向行驶,不能在障碍物的格子行驶;可以进入漩涡,但每次进入船会受伤。没走过一个格子都要消耗一升A类油。

    每个回合有两个操作:

    1.普通航行一格

    2.加速一次消耗Y升B类油,有两种加速方法,加速规则:

        a.在某一个方向连续航行d步,d步之内不能有障碍物、漩涡,不能驶出地图

        b.当下一步要驶入漩涡时,必须加速、进入漩涡后加速效果消失

    询问船是否可以到达终点,输出最少多少个回合到达,前提——船受到的伤害最小(进入漩涡次数最少),其次消耗A类油最少(走过的格子数最少),再次回合数最少。

    简述方法:限制条件的SPFA。用优先队列,不断更新符合要求的最短路径。

                            利用num[横坐标][纵坐标][受伤次数] 来记录所剩余的最大加速次数,如果后来者所存有的加速次数比先到者的多,就再走一遍。

                            利用优先队列,按照 1. 受伤次数最少  、 2. 耗A量最少   、3. 步数最少 ,按顺序进行优先级排序,依次最少的先出队列

                            这里有两个比较好的剪枝:

                                              1. 先搜索一遍,能否到达终点 

                                              2.  num[x][y][当前受伤次数-1]的位置如果已经走过,就不再走,既然少受伤一次能都路过,现在就不必再走了

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<cstring>
     
    using namespace std;
     
    const int maxn=22;
    const int fy[]={0,0,-1,1};
    const int fx[]={1,-1,0,0};
     
    struct Point{ // damage ,B-cost,A-cost 
    	int x,y,step,dmg,bcst,acst;
    	Point(){}
    	Point(int tx,int ty,int ts,int td,int ta,int tb){
    		x=tx,y=ty,step=ts,dmg=td,acst=ta,bcst=tb;
    	}
    	bool friend operator<(Point p,Point q){
    		if(p.dmg!=q.dmg) return p.dmg>q.dmg;
    		if(p.acst!=q.acst) return p.acst>q.acst;
    		return p.step>q.step;
    	}
    }; 
    struct Cdnt{ // Coordinate 
    	int x,y,cst;
    	Cdnt(){};
    	Cdnt(int tx,int ty,int tc){x=tx,y=ty,cst=tc;} 
    	bool friend operator<(Cdnt p,Cdnt q){
    		return p.cst>q.cst;
    	}
    };
    char mp[maxn][maxn];
    int n,m,sx,sy,dis; 
     
    int CBA(){ // E can be arrived ? Return the number of damage.
    	int k;
    	bool vis[maxn][maxn];
    	Cdnt now,next;
    	priority_queue<Cdnt>q;
    	memset(vis,false,sizeof(vis));
    	q.push(Cdnt(sx,sy,0));
    	vis[sx][sy]=true;
    	while(!q.empty()){
    		now=q.top();
    		q.pop();
    		if(mp[now.x][now.y]=='E') return now.cst;
    		for(k=0;k<4;k++){
    			next.x=now.x+fx[k];
    			next.y=now.y+fy[k];
    			if(next.x<0 || next.x>=n || next.y<0 || next.y>=m) continue;
    			if(vis[next.x][next.y] || mp[next.x][next.y]=='#') continue;
    			if(mp[next.x][next.y]=='*') next.cst=now.cst+1;
    			else next.cst=now.cst;
    			vis[next.x][next.y]=true; 
    			q.push(next);
    		} 
    	}
    	return -1;
    }
     
    priority_queue<Point>que;
     
    short num[maxn][maxn][maxn*maxn]; //  [x][y][number of undercurrent] for accelerate
     
    void init_(int res){
    	for(int i=0;i<n;i++)
    		for(int j=0;j<m;j++)
    			for(int k=0;k<=res;k++)
    				num[i][j][k]=-1;
    	while(!que.empty()) que.pop();
    }
     
    int bfs(int v){ // v  ->  The number of total acceleration.
    	int res,k,z;
    	Point now,next;
    	res=CBA();
    	if(res==-1 || res>v) return -1;
    	init_(res+1);
    	que.push(Point(sx,sy,0,1,0,v));
    	num[sx][sy][1]=v;
    	while(!que.empty()){
    		now=que.top();
    		que.pop();
    //		cout<<now.x<<" "<<now.y<<endl;
    		if(mp[now.x][now.y]=='E') return now.step;
    		for(k=0;k<4;k++){
    			if(now.bcst>res-now.dmg){
    				next=now;
    				for(z=0;z<dis;z++){
    					next.x+=fx[k];
    					next.y+=fy[k];
    					if(next.x>=n || next.y>=m || next.x<0 || next.y<0) break;
    					if(mp[next.x][next.y]=='#' || mp[next.x][next.y]=='*') break;
    				}
    				if(z==dis){
    					next.step++;
    					next.bcst--;
    					next.acst+=dis;
    					if(num[next.x][next.y][next.dmg]<next.bcst && num[next.x][next.y][next.dmg-1]==-1){
    						num[next.x][next.y][next.dmg]=next.bcst;
    						que.push(next);
    					}
    				}
    			}
    			next=now;
    			next.x+=fx[k];
    			next.y+=fy[k];
    			next.step++;
    			next.acst++;
    			if(next.x>=n || next.y>=m || next.x<0 || next.y<0) continue;
    			if(mp[next.x][next.y]=='#') continue;
    			if(mp[next.x][next.y]=='*'){
    				if(next.bcst>0) next.bcst--,next.dmg++;
    				else continue;
    			}
    			if(num[next.x][next.y][next.dmg]<next.bcst && num[next.x][next.y][next.dmg-1]==-1){
    				num[next.x][next.y][next.dmg]=next.bcst;
    				que.push(next);
    			}
    		}
    	}
    	return -1;
    }
     
    int main(){
    	int t,i,j,res;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d
    ",&n,&m);
    		for(i=0;i<n;i++){
    			gets(mp[i]);
    			for(j=0;j<m;j++)
    				if(mp[i][j]=='S')
    		  			sx=i,sy=j;
    		}
    		scanf("%d",&dis);
    		scanf("%d%d",&i,&j);
    		res=bfs(i/j);
    		if(res==-1) puts("can not reach!");
    		else printf("%d
    ",res);
    	}	
    	return 0;
    }

    K-dimension number

    题意:定义K-维数M:如果M的因数个数为K,则M为K-维数。题目的要求是求第N个K-维数。N<10000,Kmax<=100,Kmax是K的最大质因数。如果K是一个kk-维数,则kk<=3。

    分析:
    如果M = x1^p1 * x2^p2 * ... * xn^pn (x1,x2...xn均为质数),则 K = (p1+1)*(p2+1)*...*(pn+1). 


    这道题重要的条件是:如果K是一个kk-维数,则kk<=3。根据这个条件可以确定K的范围。kk的取值只有三种1,2,3。如果kk=1,则K=1;如果kk=2,K=p(p为质数);如果kk=3,K=p^2(p为质数)。 
      
    分情况讨论,如果K = 1,则原数M只可能为1,因为只有1的因数个数为1。如果K = p(p为质数),则原数M = x^(p-1)(x也为质数),找到第n个数只需遍历一下质数表就可以了。如果K=p^2(p为质数),则原数M = x1^(p-1)*x2^(p-1) = (x1*x2)^(p-1) (x1,x2均为质数且不等),或者 M = x1^(K-1) (x1为质数)。这种情况下找到第n个K-维数就比较复杂了,首先要找到前10000个两个不等质数之积,在对质数表和两个质数积表进行扫描,找到第n个值。 

    本题目是一个非常好的数学题,根据上面的三种情况主要有如下结论:
    1.当k=1时,结果直接为1
    2.当k=p时,结果为prime[n]^(k-1),这里的prime[n]为从2开始的第n个素数
    3.当k=p^2时,结果为p^(k-1)和(p1*p2)^(p-1)之中的第n个数(这里p1,p2为任意素数)

    当然知道结论是不够的,本题需要解决几个难点
    1.大数,这里用java解决简单了许多
    2.上述的情况三时,到底如何知道第n个数是什么呢?
    3.不断的大数运算是否会超时???这里算阶乘的时候我们全部用log算!这样节约了很多时间空间!!!

    为了解决第二个问题直观的想法就是暴力,但是绝对的超时,这个也是学到的最巧妙的一个思路。
    首先我们在最最开始的时候需要得到一个至少长度为10000的素数表(情况二就会用到了),我们在考虑情况三时往往想p1,p2值是多少然后乘起来比较大小,那么换一种思路,假如我们知道一个数a,且知道该数的一个素数约数b,那么判断a/b是否为素数,如果是说明满足了条件。

    import java.util.*;
    import java.math.*;
    import java.io.*;
    
    public class Main{
    	public static void main(String[] args){
    		final int N=105050;
    		int pnum=0;
    		int []prime = new int [10050];
    		int []pd = new int [N+5];
    		int cnt=0;
    		int []pl= new int [10050];
    		int n,k;
    		for (int i=1;i<=N;i++){
    			pd[i]=0;
    		}
    		for (int i=2;i<=N;i++){
    			if (pd[i]==0){
    				prime[++pnum]=pd[i]=i;
    			}
    			for (int j=1;j<=pnum&&i*prime[j]<=N;j++){
    				pd[i*prime[j]]=prime[j];
    				if (i%prime[j]==0){
    					break;
    				}
    			}
    		}
    		for (int i=6;i<=41200;i++){
    			int x=i/pd[i];
    			if (pd[i]!=x&&x==pd[x]){
    				pl[++cnt]=i;
    			}
    		}
    		
    		Scanner cin = new Scanner(System.in);
    		while (cin.hasNext()){
    			n=cin.nextInt();
    			k=cin.nextInt();
    			int p1=0,p2=0;
    			for (int i=1;i<=pnum;i++){
    				if (k%prime[i]==0){
    					p1=prime[i];
    					p2=k/prime[i];
    				}
    			}
    			if (k==1){
    				System.out.println(1);
    				continue;
    			}
    			if (p2==1){
    				BigInteger temp=BigInteger.valueOf(prime[n]);
    				temp=temp.pow(k-1);
    				System.out.println(temp);
    				continue;
    			}
    			if (p1==p2){
    				int i=1,j=1;
    				while (true){
    					double x=(p1*p1-1)*Math.log10(prime[i]),y=(p1-1)*Math.log10(pl[j]);
    					BigInteger sum1=BigInteger.valueOf(prime[i]).pow(p1*p1-1),sum2=BigInteger.valueOf(pl[j]).pow(p1-1);
    					if (x<=y){
    						i++;
    						if (i+j-2==n){
    							System.out.println(sum1);
    							break;
    						}
    					}else{
    						j++;
    						if (i+j-2==n){
    							System.out.println(sum2);
    							break;
    						}
    					}
    				}
    			}
    		}
    	}
    }
    

      

  • 相关阅读:
    引用jar版本错误
    一次皆大欢喜的程序员跳槽加薪
    Netty
    JAVA笔记-如何将百万级数据高效的导出到Excel表单
    100个高质量Java开发者博客
    Stackoverflow上人气最旺的10个Java问题
    偏执却管用的10条Java编程技巧
    如何生成每秒百万级别的 HTTP 请求?
    Google浏览器Chrome安装失败,错误代码0xa0430721解决办法
    Redis介绍及常用命令
  • 原文地址:https://www.cnblogs.com/Accpted/p/11310855.html
Copyright © 2011-2022 走看看