The 15th Chinese Northeast Collegiate Programming Contest

目录

 

A. Matrix

E. Easy Math Problem

K. City


A. Matrix

思路:

import java.util.*;
import java.io.*;
 
 
public class Main {
	
//	static int fm=1;
	static String sf="";
	
	static class FastScanner{
		BufferedReader br;
		StringTokenizer st;
		
		public FastScanner(InputStream in){
			br=new BufferedReader(new InputStreamReader(in),16834);
			eat("");
		}
		
		public void eat(String s) {
			st=new StringTokenizer(s);
		}
		
		public String nextLine() {
			try {
				return br.readLine();
			}catch(IOException e) {
				return null;
			}
		}
		
		public boolean hasNext() {
			while(!st.hasMoreTokens()) {
				String s=nextLine();
				sf=s;
				if(s==null)return false;
				eat(s);
			}
			return true;
		}
		
		public String next() {
			hasNext();
			return st.nextToken();
		}
		
		public int nextInt() {
			return Integer.parseInt(next());
		}
		
		public long nextLong() {
			return Long.parseLong(next());
		}
		
		public double nextDouble() {
			return Double.parseDouble(next());
		}
	}
	static FastScanner cin=new FastScanner(System.in);
	static PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	
	static int N=25000001,mod=998244353;
	static long fact[]=new long[N];
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int t=cin.nextInt();
		solve();
		while(t-->0) {
			int n=cin.nextInt();
			long ans=0;
			for(int i=1;i<=n;i++) {
				ans=(ans+C(n-1,n*n-i))%mod;
			}
			
			ans=(long)((ans*fact[n])%mod*fact[n*n-n])%mod*n%mod;
			
			out.println(ans);
			out.flush();
		}
	
	}
 
	private static long C(int b, int a) {
		// TODO Auto-generated method stub
		return fact[a]*qmi(fact[a-b],mod-2)%mod*qmi(fact[b],mod-2)%mod;
	}
 
    //快速幂求逆元
	private static long qmi(long a, long b) {
		// TODO Auto-generated method stub
		long res=1;
		while(b>0) {
			if(b%2==1)res=res*a%mod;
			a=a*a%mod;
			b/=2;
		}
		return res%mod;
	}
 
    //递归得到1-(N-1)个数的阶乘
	private static void solve() {
		// TODO Auto-generated method stub
		fact[1]=fact[0]=1;
		for(int i=2;i<N;i++) {
			fact[i]=(long)fact[i-1]*i%mod;
		}
	}
}
 

E. Easy Math Problem

思路:根据题意可以发现6是最小的完美数,所以,只需要将每一个数a乘以6并且拆分成1a+2a+3a即可;

import java.util.*;
import java.io.*;
 
public class Main {
	static class FastScanner{
		BufferedReader br;
		StringTokenizer st;
		
		public FastScanner(InputStream in){
			br=new BufferedReader(new InputStreamReader(in),16834);
			eat("");
		}
		
		public void eat(String s) {
			st=new StringTokenizer(s);
		}
		
		public String nextLine() {
			try {
				return br.readLine();
			}catch(IOException e) {
				return null;
			}
		}
		
		public boolean hasNext() {
			while(!st.hasMoreTokens()) {
				String s=nextLine();
				if(s==null)return false;
				eat(s);
			}
			
			return true;
		}
		
		public String next() {
			hasNext();
			return st.nextToken();
		}
		
		public int nextInt() {
			return Integer.parseInt(next());
		}
		
		public long nextLong() {
			return Long.parseLong(next());
		}
		
		public double nextDouble() {
			return Double.parseDouble(next());
		}
	}
	static FastScanner sc=new FastScanner(System.in);
	static PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int t=sc.nextInt();
		long k,n,p;
		while(t-->0) {
			p=sc.nextLong();
			k=6*p;
			n=3;
			out.printf("%d %d\n%d %d %d\n",k,n,p,2*p,3*p);
			out.flush();
		}
	}
 
}

K. City

思路:因为m,q的范围都很大,每一次都重新查询肯定会时间超限,那么我们可以换一个角度来想,将所有的边和所有的查询都保存下来,并且分别按照边值和查询值从大到小进行排序。然后通过并查集来合并两个连通块。因为两个连通块合并可能会出现重复加值的情况,所以需要我们每次在合并过程中都减去两个连通块各自的结果,然后加入合并之后的结果即可:

(a+b)*(a+b-1)/2-a*(a-1)/2-b*(b-1)/2

a代表第一个连通块的点数,b代表第二个连通块的点数。

import java.util.*;
import java.io.*;


public class Main {
	
//	static int fm=1;
	static String sf="";
	
	static class FastScanner{
		BufferedReader br;
		StringTokenizer st;
		
		public FastScanner(InputStream in){
			br=new BufferedReader(new InputStreamReader(in),16834);
			eat("");
		}
		
		public void eat(String s) {
			st=new StringTokenizer(s);
		}
		
		public String nextLine() {
			try {
				return br.readLine();
			}catch(IOException e) {
				return null;
			}
		}
		
		public boolean hasNext() {
			while(!st.hasMoreTokens()) {
				String s=nextLine();
				sf=s;
				if(s==null)return false;
				eat(s);
			}
			return true;
		}
		
		public String next() {
			hasNext();
			return st.nextToken();
		}
		
		public int nextInt() {
			return Integer.parseInt(next());
		}
		
		public long nextLong() {
			return Long.parseLong(next());
		}
		
		public double nextDouble() {
			return Double.parseDouble(next());
		}
	}
	static FastScanner cin=new FastScanner(System.in);
	static PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	static int N=100010;
	static rr fa[]=new rr[N];//父节点
	static long ans[]=new long[N*2];//q次查询得到的结果。
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for(int i=0;i<N;i++) {
			fa[i]=new rr();
		}
		
		int t=cin.nextInt();
		while(t-->0) {
			int n=cin.nextInt(),m=cin.nextInt();
			int q=cin.nextInt();
			
			for(int i=1;i<=n;i++) {
				fa[i].i=i;
				fa[i].sum=1;
			}
			
			r edges[]=new r[m];//记录边
			for(int i=0;i<m;i++) {
				edges[i]=new r();
				edges[i].x=cin.nextInt();
				edges[i].y=cin.nextInt();
				edges[i].k=cin.nextInt();
			}
			
			//按边权值从大到小排序
			Arrays.sort(edges,new Comparator<r>() {
				public int compare(r o1,r o2) {
					return o2.k-o1.k;
				}
			});
						
			rf b[]=new rf[q];//q次查询
			for(int i=0;i<q;i++) {
				b[i]=new rf();
				b[i].i=i;
				b[i].q=cin.nextInt();
			}
			
			Arrays.sort(b,new Comparator<rf>() {
				public int compare(rf o1,rf o2) {
					return o2.q-o1.q;
				}
			});
			
			int j=0;
			long sum=0;
			for(int i=0;i<q;i++) {
				for(;j<m;j++) {
					int x=edges[j].x,y=edges[j].y,c=edges[j].k;
					if(c<b[i].q)break;
					
					int aa=find(x);
					int bb=find(y);

					if(aa!=bb) {
						long aa1=fa[aa].sum,bb1=fa[bb].sum;
						fa[aa].i=bb;
						fa[bb].sum+=fa[aa].sum;
						
						sum+=(long)aa1*bb1;
					}
				
				}
				ans[b[i].i]=sum;
			}
			
			for(int i=0;i<q;i++) {
				out.println(ans[i]);
				out.flush();
			}
			
		}
	}

    //并查集进行查找其父节点
	private static int find(int x) {
		// TODO Auto-generated method stub
		if(fa[x].i==x)return fa[x].i;
		return fa[x].i=find(fa[x].i);
	}
}
class r{
	int x,y,k;
}
class rr{
	long sum;
	int i; 
}
class rf{
	int q,i;
}

C. Vertex Deletion

思路:本题考的是树形dp:

1.f[root][0]代表不删该节点

2.f[root][1]代表不删该节点,但删除该节点的所有子节点

3.f[root][2]代表不删该节点,只保留一个子结点

根据分析:f[root][0]=(f[j][0]+f[j][2])*f[root][0];

                   f[root][1]=f[root][1]*f[j][1];

                   f[root][2]=(hf[j][0]+f[j][1]+f[j][2])*f[root][2]-f[root][1];

f[root][2]可以通过所有合法的方案数减去所有不合法的方案数。

所以最后的结果为f[1][0]+f[1][2];

import java.util.*;
import java.io.*;
 
 
public class Main {
	
//	static int fm=1;
//	static String sf="";
	
	static class FastScanner{
		BufferedReader br;
		StringTokenizer st;
		
		public FastScanner(InputStream in){
			br=new BufferedReader(new InputStreamReader(in),16834);
			eat("");
		}
		
		public void eat(String s) {
			st=new StringTokenizer(s);
		}
		
		public String nextLine() {
			try {
				return br.readLine();
			}catch(IOException e) {
				return null;
			}
		}
		
		public boolean hasNext() {
			while(!st.hasMoreTokens()) {
				String s=nextLine();
//				sf=s;
				if(s==null)return false;
				eat(s);
			}
			return true;
		}
		
		public String next() {
			hasNext();
			return st.nextToken();
		}
		
		public int nextInt() {
			return Integer.parseInt(next());
		}
		
		public long nextLong() {
			return Long.parseLong(next());
		}
		
		public double nextDouble() {
			return Double.parseDouble(next());
		}
	}
	static FastScanner cin=new FastScanner(System.in);
	static PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	
	static int N=100010,idx=0,mod=998244353;
	static int h[]=new int[N];
	static int e[]=new int[N*2],ne[]=new int[N*2];
	static long f[][]=new long[N][3];
	
	public static void main(String[] args) {
		int t=cin.nextInt();
		
		while(t-->0) {
			int n=cin.nextInt();
			idx=0;
			Arrays.fill(h,-1);
			
			for(int i=0;i<n-1;i++) {
				int u=cin.nextInt();
				int v=cin.nextInt();
				add(u,v);add(v,u);
			}
			
			dfs(1,0);
			long ans= ((f[1][0]+f[1][2])%mod+mod)%mod; 
			out.println(ans);
			out.flush();
		}
	}
 
	private static void dfs(int root,int fa) {
		// TODO Auto-generated method stub
		f[root][0]=f[root][1]=f[root][2]=1;
		
		for(int i=h[root];i!=-1;i=ne[i]) {
			int j=e[i];
			
			if(j==fa)continue;
			
			dfs(j,root);
			
			f[root][0]=(f[j][0]+f[j][2])%mod*f[root][0]%mod;
			f[root][1]=f[j][0]%mod*f[root][1]%mod;
			f[root][2]=(f[j][0]+f[j][1]+f[j][2])%mod*f[root][2]%mod;
		}
		f[root][2]=(f[root][2]-f[root][1])%mod;
	}
 
	private static void add(int a, int b) {
		// TODO Auto-generated method stub
		e[idx]=b;ne[idx]=h[a];h[a]=idx++;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值