目录
一、第几天
思路:
利用Java中LocalDate类求解
答案:
125
代码:
import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDate;
public class Main {
static PrintWriter pw=new PrintWriter(System.out);
public static void main(String args[]) throws IOException{
LocalDate d1= LocalDate.of(2000,1,1);
LocalDate d2=LocalDate.of(2000,5,4);
int res=1;
while (!d1.equals(d2)){
res++;
d1=d1.plusDays(1);
}
pw.println(res);
pw.close();
}
}
二、方格计数
思路:
思路:
将图按上述形式建立坐标系,每个小方格用其右上方顶点代替
由于四个象限对称,因此只需要求第一象限内有多少个点与圆心的距离<=半径,再乘以4即是最终结果
答案:
7853781044
代码:
import java.io.IOException;
import java.io.PrintWriter;
public class Main {
static PrintWriter pw=new PrintWriter(System.out);
public static void main(String args[]) throws IOException{
// long res=0;
// for(long i=1;i<=50000;i++){
// for(long j=1;j<=50000;j++){
// if(i*i+j*j<=(long)Math.pow(50000,2)){
// res++;
// }
// }
// }
// pw.println(res*4);
pw.println(7853781044l);
pw.close();
}
}
四、测试次数
思路:
本题要理解最坏运气和最佳策略
最坏运气是指在每一楼层扔均有好坏两种结果,从而有不同的测试次数, 选其中的较大者,是同一层的比较。
最佳策略是指从不同楼层开始扔有不同的测试次数,在最坏运气的前提下, 选择其中的较小者,是不同楼层之间的比较
f(i,j)表示有i部手机,最高有j层楼所需要的测试次数, k代表从哪一层开始扔,按照第k层扔手机的好坏具有一下公式,每层都取其中较大者,即是最坏运气;不同层的最大值中的最小值即是最佳策略。
最终答案即是f(3,1000)
f(2,3)计算过程:选择三种的最小值,因此f(2,3)=2
f(2,4)计算过程:选择四种的最小值,因此f(2,4)=3
答案:
19
代码:
import java.io.IOException;
import java.io.PrintWriter;
public class Main{
static PrintWriter pw=new PrintWriter(System.out);
static int f[][]=new int[5][1010];//f[i][j]表示有i部手机,测试塔高为j的测试次数
public static void main(String args[]) throws IOException{
for(int i=1;i<=1000;i++){
f[1][i]=i;//只有1部手机,只能从低层开始扔,最坏运气即是每次扔都是好的,有多少层就要扔多少次
}
for(int i=2;i<=3;i++){//手机个数
f[i][1]=1;//只有一层时,只需要扔一次
for(int j=2;j<=1000;j++){//测试层数
int res=(int)2e9;
for(int k=1;k<=j;k++){//从第几层开始扔
int x= Math.max(1+f[i-1][k-1],1+f[i][j-k]);//最坏运气
res= Math.min(res,x);//最佳策略
}
f[i][j]=res;
}
}
pw.println(f[3][1000]);
pw.close();
}
}
六、递增三元组
思路:
遍历B数组,每次计算A中有多少数组比它小,记为res1,C中有多少数组比它大,记为res2,则共有res1*res2种情况,最后将每种情况相加即是最终答案
利用二分查找个数,总的时间复杂度为0(nlogn)
代码:
import java.io.*;
import java.util.Arrays;
public class Main {
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static int n;
static int N=100010;
static int a[]=new int[N];
static int b[]=new int[N];
static int c[]=new int[N];
public static void main(String args[]) throws IOException{
n=nextInt();
for(int i=1;i<=n;i++) a[i]=nextInt();
for(int i=1;i<=n;i++) b[i]=nextInt();
for(int i=1;i<=n;i++) c[i]=nextInt();
Arrays.sort(a,1,n+1);//排序,利用二分查找答案
Arrays.sort(c,1,n+1);
long res=0;
for(int i=1;i<=n;i++){
long res1=0,res2=0;
if(a[1]>=b[i]) res1=0;//a的最小值还没bi大,说明a中没有数字比它小
else{//二分找到最后一个比bi小的下标
int l=1,r=n;
while (l<r){
int mid=l+r+1>>1;
if(a[mid]<b[i]) l=mid;
else r=mid-1;
}
res1=r;
}
if(c[n]<=b[i]) res2=0;//c的最大值还没bi大,说明c中没有数字比它大
else{//二分找到第一个比bi大的下标
int l=1,r=n;
while (l<r){
int mid=l+r>>1;
if(c[mid]>b[i]) r=mid;
else l=mid+1;
}
res2=n-r+1;
}
res+=res1*res2;
}
pw.println(res);
pw.close();
}
}
七、螺旋折线
思路
将如图所示的边平移至箭头所指位置,则图就变为一个一个的正方形,将正方形从1开始进行编号,发现每个点的横纵坐标绝对值的较大值代表其在第几个正方形上,例如(-3,2)即在第三个正方形上
由于正方形的边长是一个等差数列,假设该点在第n个正方形上,其边长为2n,则其内部正方形的总边长为(2+4+6+8+···2n)*4=4*n*(n-1),每个正方形的起点为(-n,-n),因此再加上(-n,-n)到(x,y)的距离即可,按照在y=x上方还是下方分情况讨论,具体详见注释
代码:
import java.io.*;
public class Main {
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static int x,y;
static long res=0;
public static void main(String args[]) throws IOException{
x=nextInt();
y=nextInt();
int n= Math.max(Math.abs(x), Math.abs(y));//在第n个正方形上
res=4l*n*(n-1);//前n-1个正方形之和
int x1=x+n,y1=y+n;//(-n,-n)到(x,y)的横向和纵向距离
if(y>=x) res+=x1+y1;//在y=x上方,直接加上横向和纵向距离
else res+=8l*n-x1-y1;//在y=x下方,所在正方形的总边长为2n*4,减去横向和纵向距离
pw.println(res);
pw.close();
}
}
八、日志统计
思路:
创建node类存储每条记录,利用双指针算法计算在[t,t+d)区间内点赞数,判断其是否为热帖
代码:
import java.io.*;
import java.util.Arrays;
public class Main {
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static class node implements Comparable<node>{
int ts,id;
public node(int ts,int id){
this.ts=ts;
this.id=id;
}
public int compareTo(node p){
return Integer.compare(ts,p.ts);
}
}
static int n,d,k;
static int N=100010;
static node p[]=new node[N];
static boolean flag[]=new boolean[N];
static int cnt[]=new int[N];
public static void main(String args[]) throws IOException{
n=nextInt();
d=nextInt();
k=nextInt();
for(int i=0;i<n;i++){
int ts=nextInt();
int id=nextInt();
p[i]=new node(ts,id);
}
Arrays.sort(p,0,n);
for(int i=0,j=0;i<n;i++){
int id=p[i].id;
while (p[i].ts-p[j].ts>=d){
cnt[p[j].id]--;
j++;
}
cnt[id]++;
if(cnt[id]>=k) flag[id]=true;
}
for(int i=0;i<N;i++){
if(flag[i]) pw.println(i);
}
pw.close();
}
}
九、全球变暖
思路:
bfs遍历每个连通块,同时记录该连通块内的陆地个数和边界个数,若相等,等代表这个连通块将会被淹没
代码:
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
public class Main {
static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw=new PrintWriter(System.out);
static class node{
int x,y;
public node(int x,int y){
this.x=x;
this.y=y;
}
}
static int n;
static int N=1010;
static char g[][]=new char[N][N];
static boolean flag[][]=new boolean[N][N];
static int dx[]={1,-1,0,0};
static int dy[]={0,0,1,-1};
public static boolean bfs(node start){//start所在陆地连通块是否能被完全淹没
Queue<node>queue=new LinkedList<>();
queue.add(start);
flag[start.x][start.y]=true;
int cnt=1,bound=0;//陆地个数,边界靠海个数
while (!queue.isEmpty()){
node t=queue.poll();
boolean is_bound=false;//是否边界靠海
for(int i=0;i<4;i++){
int x=t.x+dx[i];
int y=t.y+dy[i];
if(x>=0 && x<n && y>=0 && y<n && !flag[x][y]){
if(g[x][y]=='.'){
is_bound=true;
}
else if(g[x][y]=='#'){
cnt++;
flag[x][y]=true;
queue.add(new node(x,y));
}
}
}
if(is_bound) bound++;
}
return cnt==bound;//若边界个数与陆地个数相等,则说明该陆地连通区域会被完全淹没
}
public static void main(String args[]) throws IOException{
n=Integer.parseInt(bf.readLine());
for(int i=0;i<n;i++){
g[i]=bf.readLine().toCharArray();
}
int res=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(!flag[i][j] && g[i][j]=='#'){
node start=new node(i,j);
if(bfs(start)) res++;
}
}
}
pw.println(res);
pw.close();
}
}
十、堆的计数
思路:
代码:
import java.io.*;
public class Main {
static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter pw=new PrintWriter(System.out);
public static int nextInt() throws IOException{
st.nextToken();
return (int)st.nval;
}
static int n;
static int N=100010;
static int s[]=new int[N];//s[i]表示以i为根的子树中的节点个数
static long f[]=new long[N];//f[i]表示以i为根的子树是小根堆的方案数,因此答案为f[1];
static long fact[]=new long[N];//求每个数的阶乘
static long infact[]=new long[N];//求每个数阶乘的逆元
static int mod=1000000009;
public static void init(){
fact[0]=infact[0]=1;
for(int i=1;i<N;i++){
fact[i]=fact[i-1]*i%mod;
infact[i]=infact[i-1]*qmi(i,mod-2,mod)%mod;
}
}
public static long qmi(long a,int k,int p){
long res=1;
while (k!=0){
if((k&1)==1) res=res*a%p;
k>>=1;
a=a*a%p;
}
return res;
}
public static long C(int a,int b){
return fact[a]*infact[b]%mod*infact[a-b]%mod;
}
public static int dfs(int u){//返回以u为根节点的树的节点个数
s[u]=1;//自身
int l=u<<1,r=u<<1|1;
if(l>n) return s[u];//没有左儿子,肯定没有右儿子,说明是叶子节点
if(l<=n) s[u]+=dfs(u<<1);
if(r<=n) s[u]+=dfs(u<<1|1);
return s[u];
}
public static void main(String args[]) throws IOException{
init();
n=nextInt();
dfs(1);//得到s数组
for(int i=n/2+1;i<=n;i++) f[i]=1;//第一个叶子节点的下标为n/2+1,初始化叶子节点,方案数为1
for(int i=n/2;i>=1;i--){//n/2为最后一个非叶子节点
int l=i<<1,r=i<<1|1;
f[i]=C(s[i]-1,s[l]);
f[i]=f[l]*f[i]%mod;
if(r<=n) f[i]=f[i]*f[r]%mod;//非叶子节点一定有左儿子,不一定有右儿子,因此需要加判断
}
pw.println(f[1]);
pw.close();
}
}