目录
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代表第二个连通块的点数。
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++;
}
}