题目链接
知识一览
01 - 数学/模拟
02 - 背包问题
03 - 质因数/dfs搜索
04 - 二分/并查集
题目列表
快输
static class FastReader{
BufferedReader br;
StringTokenizer st;
String tmp;
public FastReader() {
br=new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while(st==null||!st.hasMoreElements()) {
try {
st=new StringTokenizer(br.readLine());
}catch(IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong(){return Long.parseLong(next());}
String nextLine() {
String str="";
try {
str=br.readLine();
}catch(IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext(){
if(st!=null&&st.hasMoreTokens())return true;
try {
tmp=br.readLine();
st=new StringTokenizer(tmp);
}catch(IOException e) {
return false;
}
return true;
}
}
static PrintWriter out=new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
static FastReader sc=new FastReader();
C - KartRider(数学/模拟)
题目链接:C
题目描述
已知游乐场有两条卡丁车赛道,赛道1的起点到终点距离为n,赛道2的起点到终点距离为m。
区别于传统的卡丁车,这里的卡丁车采用自动驾驶技术,且驾驶员不能在行驶过程中改变车子速度。
车子的速度遵循如下规律:第1秒内速度为1,第2秒内速度为2… 第 k秒内速度为k,车子的移动时间每增加1秒,其速度也加1。
此外,车子运动过程中可以在整数秒点人为改变运动方向,可以向前,也可以向后,也就是说:车手不能在0.5这种小数秒点改变车子的运动方向。
而且车子一旦启动,就不能在到达终点之前停止运动(必须在整数秒点到达终点,非整数秒点经过终点不被认作到达终点)。
经过石头剪刀布,Tari 选择在赛道1上驾驶赛车,Erini 选择在赛道2上驾驶赛车。
假设他们都采用了最佳策略,问:谁能用更短的时间到达终点,输出胜利者的名字和所用时间;如果两个人打成平手,输出 “Draw”。
输入描述:
输入两个正整数n和m,分别表示 Tari 和 Erini 从出发位置到终点的距离(0≤n,m≤10^9)。
输出描述:
输出胜利者的姓名和他到达终点时所用时间,中间用空格隔开;如果同时到达终点,输出"Draw"。
示例1
输入
3 2
输出
Tari 2
说明
Tari 的最佳驾驶策略:第 1 秒到达 1,第 2 秒到达 3(因为第 2 秒内卡丁车的速度为 2),所需时间为 2 秒。
Erini 的最佳驾驶策略:第 1 秒到达 1,然后第 2 秒反向行驶到 -1,第 3 秒再正向行驶到 2(2=1-2+3),所需时间为 3 秒。
示例2
输入
10 10
输出
Draw
public static void main(String[] args) {
//int T=sc.nextInt();
int T=1;
while(T-->0){
solve();
}
}
private static void solve(){
long n=sc.nextLong(),m=sc.nextLong();
long ans1=f(n),ans2=f(m);
if(ans1<ans2){
out.printf("%s %d\n","Tari",ans1);
}else if(ans1==ans2){
out.printf("Draw\n");
}else{
out.printf("%s %d\n","Erini",ans2);
}
out.flush();
}
private static long f(long a){
if(a==0)return 0;
long res=0;
for(int i=1;;i++){
res+=i;
if(res>=a){
long t=res-a;
if((t&1)==0)return i;
else if((i&1)==1) return i+2;
else return i+1;
}
}
}
F - Archery(背包问题)
题目链接: F
题目描述
比赛规则如下:运动场上有n个箭靶,编号为1-n,射中编号为i 的箭靶可以得到i×10分(i∈[1,n])。
但如果累计射中编号为i的箭靶靶心 ai次,那么选手可以额外获得bi的奖励分。同时比赛也规定,箭靶i最多被射中ai次,超出 ai不计分。
集训队的小明报名参加了本项射箭比赛,现在他邀请聪明的你帮他计算一下,他最少需要射出几箭,才能保证他的得分不低 k。
如果小明无论射出多少箭都无法获得大于等于k的得分,那么输出"wa"。
输入描述:
第1行输入正整数n,kn,k(1≤n≤10,10≤k≤10^9),表示运动场内箭靶的数量以及小明在射箭比赛中的最少得分。
第 2−n+1行每行输入两个正整数ai,bi(1≤ai≤100,10≤bi≤10^5),中间用空格隔开,含义如上文所述。
输出描述:
输出答案。
示例1
输入
2 70
3 50
5 80
输出
3
说明
小明可以选择在编号为 1 的箭靶上射箭 3 次,在得到基础分 30 分的前提下,他还可以得到奖励分 50 分,总分 80 分\geq k≥k,这是最佳策略,答案等于 3。
示例2
输入
2 40
3 50
5 80
输出
2
说明
小明可以选择在编号为2的箭靶上射箭 2 次,得分为2\times 20=40\geq k2×20=40≥k,此举为最佳策略,答案等于 2。
public static void main(String[] args) {
//int T=sc.nextInt();
int T=1;
while(T-->0){
solve();
}
}
private static void solve(){
int n=sc.nextInt();
long k=sc.nextLong();
int a[]=new int[n+1],b[]=new int[n+1];
int sum=0;
for(int i=1;i<=n;i++) {
a[i]=sc.nextInt();
b[i]=sc.nextInt();
sum+=a[i];
}
int dp[]=new int[sum+1];
for(int i=1;i<=n;i++) {
for(int j=sum;j>=1;j--) {
for(int m=1;m<a[i];m++) {
if(j>=m) dp[j]=Math.max(dp[j],dp[j-m]+10*i*m);
}
if(j>=a[i]) dp[j]=Math.max(dp[j],dp[j-a[i]]+10*i*a[i]+b[i]);
}
}
boolean f=false;
for(int i=0;i<=sum;i++) {
if(dp[i]>=k) {
out.println(i);f=true;break;
}
}
if(!f)out.println("wa");
out.flush();
}
G - Function(质因数/dfs搜索)
static long prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};//16 : 0-15
static long ans=0,n;
public static void main(String[] args) {
int T=sc.nextInt();
//int T=1;
while(T-->0){
solve();
}
}
private static void solve(){
ans=0;
n=sc.nextLong();
dfs(1,1,0,60);
out.println(ans);
out.flush();
}
static void dfs(long cnt,long cur,int idx,int M){
if(idx==16)return;
if(cnt>ans)ans=cnt;
for(int i=1;i<=M;i++){
//注意cur*prime[idx]可能爆long
if(n/prime[idx]<cur) break;
cur*=prime[idx];
dfs(cnt*(i+1),cur,idx+1,i);
}
}
H - Tree(二分/并查集)
static int n,s;
static long c[]=new long[N];
static int a[]=new int[N],f[]=new int[N],u[]=new int[N],v[]=new int[N],d[]=new int[N];
public static void main(String[] args) {
//int T=sc.nextInt();
int T=1;
while(T-->0){
solve();
}
}
private static void solve(){
n=sc.nextInt();//n个节点的树
s=sc.nextInt();//需要获取价值总和至少为s的宝石
for(int i=2;i<=n;i++) a[i]=sc.nextInt();//编号 2-n 节点上的宝石价值
for(int i=1;i<n;i++) {//从节点u经过链duv走到节点v
u[i]=sc.nextInt();
v[i]=sc.nextInt();
d[i]=sc.nextInt();
}
int l=0,r=(int)2e9,mid;
while(l<=r){
mid=l+r>>1;
if(check(mid))r=mid-1;
else l=mid+1;
}
out.println(l);
out.flush();
}
static int find(int x){
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
static void merge(int x,int y){
int fx=find(x),fy=find(y);
f[fx]=fy;
c[fy]+=c[fx];
}
static boolean check(int mid){
for(int i=1;i<=n;i++) {
f[i]=i;
c[i]=a[i];
}
for(int i=1;i<n;i++){
if(mid>=d[i]) merge(u[i],v[i]);
}
return c[find(1)]>=s;
}