原题链接: 算法训练 区间k大数查询
思路: 数据挺小的吧,暴力即可。对于m次询问,用一个数组 b[i] 暂存数组a[l] ~ a[r] 的值,然后从大到小排下序,输出该区间第 k 个数。
注意: 每次询问先将数组 b[i] 初始化为0 !!!
C++ Code:
#include
#include
#include
using namespace std;
int a[100100];
int b[100100];
bool cmp(int a,int b){
return a>b;
}
int main(){
int n; cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
int m; cin>>m;
while(m--){
memset(b,0,sizeof(b));
int l,r,k;
cin>>l>>r>>k;
for(int i=l;i<=r;i++)
b[i]=a[i];
sort(b+l,b+r+1,cmp);
cout<<b[l+k-1]<<endl;
}
}
Java Code:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int[] a = new int[10010];
static int[] b = new int[10010];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
for(int i=1;i<=n;i++)
a[i] = cin.nextInt();
int m = cin.nextInt();
while(m-- >0) {
int l = cin.nextInt();
int r = cin.nextInt();
int k = cin.nextInt();
for(int i=l;i<=r;i++)
b[i]=a[i];
Arrays.sort(b,l,r+1);
System.out.println(b[r-k+1]);
}
}
}
原题链接:算法训练 传纸条
一共分四种情况:
1. dp[i][j][k][l] = dp[i-1][j][k-1][l] //两次都是从上面走下来的
2. dp[i][j][k][l] = dp[i][j-1][k][l-1] //两次都是从左边走过来的
3. dp[i][j][k][l] = dp[i-1][j][k][l-1] //第一次从上面走来,第二次从左边走来
4. dp[i][j][k][l] = dp[i][j-1][k-1][l] //第一次从左边走来,第二次从上面走来
状态转移方程:
dp[i][j][k][l]=max(max(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1]),max(dp[i-1][j][k][l-1],dp[i][j-1][k-1][l]))+a[i][j]
同时还要判断两次走的路径是否相交:
if(i!=k&&j!=l) dp[i][j][k][l]+=a[k][l];
C++ Code:
#include
#include
using namespace std;
int a[55][55];
int dp[55][55][55][55];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=1;k<=n;k++){
for(int l=1;l<=m;l++){
int x=max(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1]);
int y=max(dp[i-1][j][k][l-1],dp[i][j-1][k-1][l]);
dp[i][j][k][l]=max(x,y)+a[i][j];
if(i!=k && j!=l)
dp[i][j][k][l]+=a[k][l];
}
}
}
}
cout<<dp[n][m][n][m]<<endl;
return 0;
}
Java Code:
import java.util.Scanner;
public class Main {
public static int[][] a = new int[55][55];
public static int[][][][] dp = new int[55][55][55][55];
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = cin.nextInt();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j] = cin.nextInt();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=1;k<=n;k++){
for(int l=1;l<=m;l++){
int x=Math.max(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1]);
int y=Math.max(dp[i-1][j][k][l-1],dp[i][j-1][k-1][l]);
dp[i][j][k][l]=Math.max(x,y)+a[i][j];
if(i!=k && j!=l)
dp[i][j][k][l]+=a[k][l];
}
}
}
}
System.out.println(dp[n][m][n][m]);
}
}
原题链接:算法训练 Hankson的趣味题
题意: 求出满足条件的 x 的个数:gcd(x,a0) = a1,lcm(x,b0) = b1。
思路: 这道题暴力枚举只能过部分的点。其实这是一道数论题。x 是 a1的整数倍且是 b1 的因子,所以可以枚举 b1 的因子,也就是 x,如果这个数是 a1 的整数倍,并且满足那两个式子,则 ans++。找到 x 的时候要注意是否存在 b1 的另一个因子 y 。
重要结论: 对于两个正整数a,b,设 gcd(a, b)=k,则存在gcd(a/k, b/k)=1
具体证明过程见大佬博客:NOIP2009Hankson的趣味题
Code1: 暴力枚举法,不能全部 AC。
import java.util.Scanner;
public class Main {
static long gcd(long a,long b) {
return a%b==0?b:gcd(b,a%b);
}
static long lcm(long a,long b) {
return a*b/gcd(a,b);
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
while(t-- >0) {
long a0 = cin.nextLong();
long a1 = cin.nextLong();
long b0 = cin.nextLong();
long b1 = cin.nextLong();
int x=0,ans=0;
for(int i=1;i<10000000;i++) {
if(gcd(i,a0)==a1) {
x=i;
break;
}
}
for(int i=x;i<=b1;i++) {
if(lcm(i,b0)==b1)
ans++;
}
System.out.println(ans);
}
}
}
Code2: 用 long 型只能过部分样例,事实证明不能随便用 long 型。
import java.util.Scanner;
public class Main {
static int gcd(int a,int b) {
return b==0?a:gcd(b,a%b);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
int t = cin.nextInt();
while(t-- >0) {
int a0 = cin.nextInt();
int a1 = cin.nextInt();
int b0 = cin.nextInt();
int b1 = cin.nextInt();
int p = a0/a1, q = b1/b0, ans=0;
for(int x=1;x*x<=b1;x++) {
if(b1%x==0) {
if(x%a1==0 && gcd(x/a1,p)==1 && gcd(q,b1/x)==1) ans++;
int y = b1/x;
if(x==y) continue;
if(y%a1==0 && gcd(y/a1,p)==1 && gcd(q,b1/y)==1) ans++;
}
}
System.out.println(ans);
}
}
}
原题链接:算法训练 接水问题
C++ Code:
#include
#include
using namespace std;
int w[100000];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>w[i];
int ans=0,t=m; //ans表示所需时间,t表示替换到第t位同学
if(n<=m){ //人数小于等于水龙头数直接输出最大的
sort(w+1,w+1+n);
cout<<w[n]<<endl;
}else{
while(w[m]){ //当第m个水龙头还有人
sort(w+1,w+1+m);
while(w[1]){ //只要第一个水龙头的人未装满就时间就一直增加
for(int i=1;i<=m;i++)
w[i]--;
ans++;
}
w[1]=w[t+1]; //更替下一位同学
if(t+1==n){ //如果剩下m位同学直接输出剩下的所需时间最大的就可以了
sort(w+1,w+1+m);
ans+=w[m];
cout<<ans<<endl;
return 0;
}
t++;
}
}
}
Java Code:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int[] a = new int[10010];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = cin.nextInt();
for(int i=1;i<=n;i++)
a[i] = cin.nextInt();
if(n<=m) {
Arrays.sort(a,1,n+1);
System.out.println(a[n]);
}
else {
int ans=0,t=m;
while(a[m]>0) {
Arrays.sort(a,1,m+1);
while(a[1]>0) {
for(int i=1;i<=m;i++)
a[i]--;
ans++;
}
a[1]=a[t+1];
if(t+1==n) {
Arrays.sort(a,1,m+1);
ans+=a[m];
System.out.println(ans);
break;
}
t++;
}
}
}
}
原题链接:算法训练 调和数列问题
思路: 一道水题,直接遍历寻找答案,记得减掉1。
注意: 不能用 1 / i ,而是 1.0 / i ,以及判断语句的位置要注意。
C++ Code:
#include
using namespace std;
int main(){
double x;
while(cin>>x && x!=0.00){
double ans=0.0;
for(int i=2;;i++){
ans+=(1.0/i); //注意因为结果是浮点数,所以要用1.0来除
if(ans>=x){ //判断语句要放在这里
cout<<i-1<<" card(s)"<<endl;
break;
}
}
}
return 0;
}
Java Code:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
double x = cin.nextDouble();
if(x==0.00) break;
int i;
double ans=0.0;
for(i=1;;i++) {
ans+=1.0/(i+1);
if(ans>=x) break;
}
System.out.println(i+" card(s)");
}
}
}
原题链接:算法训练 Hanoi问题
C++ Code1:
#include
using namespace std;
int ans;
void hanoi(int n,int m,char a,char b,char c){
if(n<=m)
ans++;
else{
hanoi(n-m,m,a,c,b);
ans++;
hanoi(n-m,m,b,a,c);
}
}
int main(){
int n,m;
cin>>n>>m;
hanoi(n,m,'x','y','z');
cout<<ans<<endl;
return 0;
}
/*
一般汉诺塔问题代码:
#include
using namespace std;
int ans;
void hanoi(int n,char a,char b,char c){
if(n==1)
ans++;
else{
hanoi(n-1,a,c,b);
ans++;
hanoi(n-1,b,a,c);
}
}
int main(){
int n,m;
cin>>n;
hanoi(n,'x','y','z');
cout<
C++ Code2:
//递归得出公式 f(n) = 2f(n)+1, 然后通过数学推算得通项公式为 f(n) = 2^n-1
#include
#include
using namespace std;
int main(){
int n,m;
cin>>n>>m;
if(n%m!=0)
n=n/m+1;
else
n/=m;
cout<<pow(2,n)-1<<endl;
}
Java Code:
import java.util.Scanner;
public class Main {
private static int ans=0;
public static void hanoi(int n,int m,char a,char b,char c) {
if(n<=m)
ans++;
else {
hanoi(n-m,m,a,c,b);
ans++;
hanoi(n-m,m,b,a,c);
}
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = cin.nextInt();
hanoi(n,m,'x','y','z');
System.out.println(ans);
}
}
原题链接:算法训练 蜜蜂飞舞
C++ Code:
#include
#include
#include
using namespace std;
int main(){
int n; cin>>n;
int a,b,c,d,e,f,t;
int x1=0,y1=0,z1=0,x2=0,y2=0,z2=0;
for(int i=1;i<=n;i++){
cin>>a>>b>>c>>d>>e>>f>>t;
x1+=a*t,y1+=b*t,z1+=c*t;
x2+=d*t,y2+=e*t,z2+=f*t;
}
int sx1,sy1,sz1,sx2,sy2,sz2;
cin>>sx1>>sy1>>sz1>>sx2>>sy2>>sz2;
x1+=sx1,y1+=sy1,z1+=sz1;
x2+=sx2,y2+=sy2,z2+=sz2;
double ans=sqrt(pow((x1-x2),2)+pow((y1-y2),2)+pow((z1-z2),2));
printf("%.4f",ans);
}
Java Code:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int a,b,c,d,e,f,t;
int x1=0,y1=0,z1=0,x2=0,y2=0,z2=0;
while(n-- >0){
a = cin.nextInt(); b = cin.nextInt();
c = cin.nextInt(); d = cin.nextInt();
e = cin.nextInt(); f = cin.nextInt();
t = cin.nextInt();
x1+=a*t; y1+=b*t; z1+=c*t;
x2+=d*t; y2+=e*t; z2+=f*t;
}
int xx1 = cin.nextInt(); int yy1 = cin.nextInt();
int zz1 = cin.nextInt(); int xx2 = cin.nextInt();
int yy2 = cin.nextInt(); int zz2 = cin.nextInt();
x1+=xx1; y1+=yy1; z1+=zz1;
x2+=xx2; y2+=yy2; z2+=zz2;
double ans = Math.sqrt(Math.pow(x1-x2, 2)+Math.pow(y1-y2, 2)+Math.pow(z1-z2, 2));
System.out.printf("%.4f\n",ans);
}
}
原题链接:算法训练 数组查找及替换
Java Code:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int[] a = new int[105];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
int n = cin.nextInt(); int b = cin.nextInt();
for(int i=1;i<=n;i++)
a[i] = cin.nextInt();
Arrays.sort(a,1,n+1);
for(int i=1;i<=n;i++) {
if(a[i]%b!=0) {
if(a[i]>='A'&&a[i]<='Z')
System.out.print((char)a[i]+" ");
else
System.out.print(a[i]+" ");
}
}
}
}
原题链接:算法训练 比赛安排
Java Code:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int[][] pair = new int[70][70];
static int[] team = new int[70];
static int n;
static void race() {
int x=0;
Arrays.fill(team, 0);
for(int i=1;i<=n;i++) {
for(int j=i+1;j<=n;j++) {
if(pair[i][j]==0 && team[i]==0 && team[j]==0) {
x++;
team[i]=1; team[j]=1; pair[i][j]=1;
System.out.print(i+"-"+j+" ");
}
if(x==n/2) return;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
n = cin.nextInt();
n = (int) Math.pow(2, n);
for(int k=1;k<n;k++) {
System.out.printf("<%d>",k);
race();
System.out.println();
}
}
}
原题链接:算法训练 字符串编辑
Java Code:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub\
Scanner cin = new Scanner(System.in);
String s1 = cin.nextLine();
String s2 = cin.nextLine();
char ch = s2.charAt(0);
if(ch=='D') {
int x = -1;
x = s1.indexOf(s2.charAt(2));
if(x==-1)
System.out.println("指定字符不存在");
else
System.out.println(s1.replaceFirst(s1.substring(x, x+1), ""));
}else if(ch=='I') {
int sum=0,x = -1;
for(int i=0;i<s1.length();i++) {
if(s1.charAt(i)==s2.charAt(2))
sum++;
}
if(sum==0)
System.out.println("指定字符不存在");
else if(sum==1){
x = s1.indexOf(s2.charAt(2));
System.out.println(s1.substring(0,x)+s2.charAt(4)+s1.substring(x));
}else {
for(int i=s1.length()-1;i>=0;i--) {
if(s1.charAt(i)==s2.charAt(2)) {
x = i;
break;
}
}
System.out.println(s1.substring(0,x)+s2.charAt(4)+s1.substring(x));
}
}else if(ch=='R') {
int x = -1;
x = s1.indexOf(s2.charAt(2));
if(x==-1)
System.out.println("指定字符不存在");
else
System.out.println(s1.replace(s1.substring(x, x+1), s2.substring(4,5)));
}
}
}