题目描述
数列A1,A1,…,AN ,修改最少的数字,使得数列严格单调递增。
输入
第 1 行,1 个整数 N 第 2 行,N 个整数 A1,A1,…,AN
。(1 ≤ N ≤ 10^5,1≤ Ai ≤10^9)
输出
1 个整数,表示最少修改的数字 。
样例输入 Copy
3
1 2 3
5
1 2 9 3 4
样例输出 Copy
0
1
维护一个单调队列,这个队列的元素是严格单调递增的,当我们增加一个新元素去和单调队列的最后一个元素比较,如果比最后一个元素大,就入队,否则,就将该元素插入到本应该在队列中的某一位置(二分)
import java.util.Scanner;
public class Main{
static int n=500;
static int r=0;
static int arr[]=new int[n+1];
static int temp[]=new int[n+1];
public static int find(int x) {//二分查找某个元素应在的位置
int mid, left=1,right=r;
while(left<right) {
mid=(left+right)>>1;
if(x==temp[mid])
return mid;
if(x>temp[mid])
left=mid+1;
else
right=mid;
}
return right;
}
public static void main(String args[]){
Scanner cin = new Scanner(System.in);
while(cin.hasNext()){
int n=cin.nextInt();
for(int i=1;i<=n;i++) {
arr[i]=cin.nextInt();
}//输入
for(int i=1;i<=n;i++)
{
if(arr[i]>temp[r])
temp[++r]=arr[i];//入队
else
temp[find(arr[i])]=arr[i];//去查找该元素在队列中应在的位置
}
System.out.println(n-r);
r=0;//使r重新回到0;继续下一次执行的初始化
}
}
}
题目描述
使用动态规划算法求解矩阵连乘问题,输出最少乘法次数。
输入
每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。
输出
矩阵连乘最优计算次数。
样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
15125
import java.util.Scanner;
public class Main{
public static void martixChain(int p[],int m[][]) {
int n=p.length-1;
for(int i=1;i<=n;i++) {m[i][i]=0;}
for(int r=2;r<=n;r++) {//长度
for(int i=1;i<=n-r+1;i++) {//每一个对角线的元素个数
int j=i+r-1;//列
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
for(int k=i+1;k<j;k++) {
int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if (t < m[i][j]) {
m[i][j] = t;
}
}
}
}
}
public static void main(String args[]){
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
int n=cin.nextInt();
int p[]=new int[n];//存维度
for(int i=0;i<n;i++) {
p[i]=cin.nextInt();
}
int m[][]=new int[n][n];//m为存取最少存取次数
martixChain(p,m);
System.out.println(m[1][n-1]);
}
}
}
题目描述
使用动态规划算法求解矩阵连乘问题。
输入
每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。
输出
矩阵连乘最优计算次序。
样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
A[2:2] * A[3:3]
A[1:1] * A[2:3]
A[4:4] * A[5:5]
A[4:5] * A[6:6]
A[1:3] * A[4:6]
import java.util.Scanner;
public class Main{
public static void martixChain(int p[],int m[][],int s[][]) {
int n=p.length-1;
for(int i=1;i<=n;i++) {m[i][i]=0;}
for(int r=2;r<=n;r++) {//长度
for(int i=1;i<=n-r+1;i++) {//每一个对角线的元素个数
int j=i+r-1;//列
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j] = i;
for(int k=i+1;k<j;k++) {
int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if (t < m[i][j]) {
m[i][j] = t;
s[i][j]=k;
}
}
}
}
}
public static void traceback(int s[][],int i,int j) {
if(i==j)return ;
traceback(s, i, s[i][j]);
traceback(s, s[i][j]+1, j);
//A[2:2] * A[3:3]
System.out.println("A["+i+":"+s[i][j]+"] * A["+(s[i][j]+1)+":"+j+"]");
}
public static void main(String args[]){
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
int n=cin.nextInt();
int p[]=new int[n];//存维度
for(int i=0;i<n;i++) {
p[i]=cin.nextInt();
}
int m[][]=new int[n][n];//m为存取最少存取次数
int s[][]=new int[n][n];
martixChain(p,m,s);
traceback(s,1,n-1);
}
}
}
题目描述
在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。例如:输入{1,2,3,4,5},输出33。【3+6+9+15=33】
输入
本题应该处理到文件尾,每组输入包括两行,第一行为石子堆的个数n,第二行则为每堆石子的个数。
输出
输出最小花费。
样例输入 Copy
5
1 2 3 4 5
样例输出 Copy
33
import java.util.Scanner;
public class Main{
public static void main(String args[]){
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
int n=cin.nextInt();
int dp[][]=new int [n+1][n+1];
int sum[][]=new int[n+1][n+1];
int arr[]=new int[n+1];
for(int i=1;i<=n;i++) {
arr[i]=cin.nextInt();//输入
}
for(int i=1;i<n;i++)
{
sum[i][i]=arr[i];
for(int j=i+1;j<=n;j++)
{
sum[i][j]=sum[i][j-1]+arr[j];//合并区间i到j的结果
}
}
for(int r=2;r<=n;r++)//区间长度为 r的最小值
{
for(int i=1;i<=n-(r-1);i++)//枚举区间长度的开头
{
int j=i+(r-1);//区间长度固定,根据开头求出结尾
dp[i][j]=999999999;
for(int k=i;k<j;k++)//枚举出合并这段区间以前的最小花费
{
dp[i][j]=Math.min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
dp[i][j] += sum[i][j];//加上这一段合并的花费
}
}
System.out.println(dp[1][n]);
}
}
}
时间限制: 3 Sec 内存限制: 128 MB
提交: 6 解决: 1 外部导入
提交状态讨论版
题目描述
你有一个日志文件,里面记录着各种系统事件的详细信息。自然的,事件的时间戳按照严格递增顺序排列(不会有两个事件在完全相同的时刻发生)。
遗憾的是,你的系统被病毒感染了,日志文件中混入了病毒生成的随机伪事件(但真实事件的相对顺序保持不变)。备份的日志文件也被感染了,但由于病毒采用的随机感染方法,主日志文件和备份日志文件在感染后可能会变得不一样。
给出被感染的主日志和备份日志,求真实事件序列的最长可能长度。
输入
输入第一行为数据组数T (T<=100)。每组数据包含两行,分别描述感染后的主日志和备份日志。每个日志文件的格式相同,均为一个整数n (1<=n<=1000)(代表感染后的事件总数)和n 个不超过100,000的正整数(表示感染后各事件的时间戳)。注意,感染后可能会出现时间戳完全相同的事件。
输出
对于每组数据,输出真实事件序列的最长可能长度。
样例输入 Copy
1
9 1 4 2 6 3 8 5 9 1
6 2 7 6 3 5 1
样例输出 Copy
3
最长递增子序列
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
static int f[][]= {};
static int ans=0;
public static void solve(int f[][],int a[],int b[],int n,int m) {
for(int i=1; i<=n; i++){
int v=0; //v代表b[k]
for(int j=1; j<=m; j++){
if(a[i]==b[j]) f[i][j]=v+1;
else f[i][j]=f[i-1][j];
//j即将增大为j+1,检查j能否进入新的决策集合
if(b[j]<a[i]) v=Math.max(v,f[i-1][j]);
}
}
for(int j=1; j<=m; j++) ans=Math.max(ans,f[n][j]);
}
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
{
int T;
T=cin.nextInt();
while(T>0) {
int n=cin.nextInt();
int a[]=new int[n+1];
for(int i=1;i<=n;i++) {
a[i]=cin.nextInt();
}//第一个主日志
int m=cin.nextInt();
int b[]=new int[m+1];
for(int i=1;i<=m;i++) {
b[i]=cin.nextInt();
}//第二个备份日志
f=new int[n+1][m+1];
solve(f,a,b, n, m);
System.out.println(ans);
ans=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
f[i][j]=0;
}
}
T--;
}
}
}
}
题目描述
“今年暑假不AC?”
“是的。”
“那你干什么呢?”
“看世界杯呀,笨蛋!”
“@#$%^&*%…”
确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视了。
作为球迷,一定想看尽量多的完整的比赛,当然,作为新时代的好青年,你一定还会看一些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)
输入
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
输出
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
样例输入 Copy
12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0
样例输出 Copy
5
import java.awt.List;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
class Tv
{
int start;
int end;
public Tv(int start,int end) {
this.start=start;
this.end=end;
}
};//定义一个结构体,存开始和结束时间
//排序
class cmp implements Comparator<Tv>{
@Override
public int compare(Tv a, Tv b) {
if(a.end<b.end) {
return 1;
}else {
return -1;
}
}
}
public class Main {
public static void main(String[] args) {
Comparator<Tv> com=new Comparator<Tv>() {
@Override
public int compare(Tv p1,Tv p2){
if(p1.end!=p2.end)//先按照节目结束时间排序
{
return p1.end-p2.end;
}
else//若结束时间相同,则按照开始时间排序
{
return p1.start-p2.start;
}
}
};
Scanner cin=new Scanner(System.in);
while(cin.hasNext()) {
int m=cin.nextInt();//节目数
if(m==0) {
break;
}
ArrayList<Tv> list=new ArrayList<Tv>();
for(int i=0;i<m;i++) {
int start=cin.nextInt();
int end=cin.nextInt();
Tv tv=new Tv(start,end);
list.add(tv);//将对象存入数组中
}
Collections.sort(list,com);
int j=0;
int count=1;//计数
for(int i=1;i<m;i++) {
if(list.get(i).start>=list.get(j).end) {
j=i;
count++;
}
}
System.out.println(count);
}
}
}
题目描述
编程实现Kruskal算法,求图的最小生成树(MST)的权重。
输入
每组数据分为两个部分,第一部分为图的点数n,和边数m,
第二部分为m行,每一行输入三个数字,前两个为两个顶点的编号,第三个为边权重。
输出
最小生成树的权重。
样例输入 Copy
3 3
0 1 10
0 2 15
1 2 50
样例输出 Copy
25
并查集+排序
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
class edge{
int x,y;//点
int w;//边
};
//排序
class cmp implements Comparator
{
public int compare(edge a, edge b) {
if(a.wrank[y]) {
pa[y]=x;
}else {
pa[x]=y;
if(rank[x]==rank[y]) {
rank[y]++;
}
}
sum+=w;
return 1;
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
//while(cin.hasNext()) {
edge e[]=new edge[1000];//存边与边之间的信息
int n=cin.nextInt();//图的点
int m=cin.nextInt();//边数
for(int i=0;i
题目描述
众所周知,牛妹非常喜欢吃蛋糕。
第一天牛妹吃掉蛋糕总数三分之一多一个,第二天又将剩下的蛋糕吃掉三分之一多一个,以后每天吃掉前一天剩下的三分之一多一个,到第n天准备吃的时候只剩下一个蛋糕。
牛妹想知道第一天开始吃的时候蛋糕一共有多少呢?
输入
输入n,0 输出 输出第一天蛋糕的数量。 样例输入 Copy 2 样例输出 Copy 3 dp,首先先将dp数组的第一行和第一列初始化 时间限制: 1 Sec 内存限制: 128 MB 提交: 0 解决: 0 admin 提交状态讨论版 题目描述 验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和。 例如: 1^3=1 2^3=3+5 3^3=7+9+11 4^3=13+15+17+19 输入 多组输入,输入一个整数。 输出 输出分解后的字符串。 样例输入 Copy 6 样例输出 Copy 31+33+35+37+39+41 时间限制: 1 Sec 内存限制: 128 MB 提交: 0 解决: 0 admin 提交状态讨论版 题目描述 一个DNA序列由A/C/G/T四个字母的排列组合组成。G和C的比例(定义为GC-Ratio)是序列中G和C两个字母的总的出现次数除以总的字母数目(也就是序列长度)。在基因工程中,这个比例非常重要。因为高的GC-Ratio可能是基因的起始点。 给定一个很长的DNA序列,以及要求的最小子序列长度,研究人员经常会需要在其中找出GC-Ratio最高的子序列。 输入 输入一个字符串型基因序列和整型子串的长度。 输出 找出GC比例最高的子串,如果有多个输出第一个的子串。 样例输入 Copy AACTGTGCACGACCTGA 样例输出 Copy GCACG 提示 字符串长度<=100000 两重循环,第二层用于确定cg的数量以及下标,同时用index记录最大的那个cg的下标 时间限制: 1 Sec 内存限制: 128 MB 提交: 636 解决: 105 201501010119 提交状态讨论版 题目描述 如果实施更为严格的防控措施,一辆汽车上有一个确诊患者或者密切接触者,那么该汽车上所有的人都被认为是密切接触者,全部需要自行居家隔离或者集中隔离14天。 输入 第1行的第1个数字n表示总人数,第2个数字m表示汽车数量;从第2行开始,接下来的m行表示每辆汽车的司乘人员总人数和人员编号(人员编号是一个固定值,可以对应于我们的身份证号码),每一行的第1个数字k表示该汽车的司乘人员总数,接下来的k个数字表示每一个人的编号。 输出 需要被隔离的总人数。 样例输入 Copy 100 4 样例输出 Copy 4 并查集,然后用cout记录要隔离的人数,在find_set(i)中寻找根节点为0的,找到就count++; 时间限制: 1 Sec 内存限制: 128 MB 提交: 228 解决: 122 201501010119 提交状态讨论版 题目描述 编程实现Dijkstra算法,求一个有向加权图中,从源点出发到其他各个顶点的最短路径。 输入 第1行第1个值表示顶点个数,第2个值表示边个数;第2行开始为边(两个顶点,边的起点和终点)及权重。 输出 顶点0到每一个顶点的最短路径长度。 样例输入 Copy 5 7 样例输出 Copy 0 10 50 30 60
4
10思路:
代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
int n=cin.nextInt();
int m=cin.nextInt();
int map[][]=new int[n+1][m+1];
int dp[][]=new int[n+1][m+1];
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
map[i][j]=cin.nextInt();
}
}
/*for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
System.out.print(map[i][j]+" ");
}
System.out.println();
}*/
dp[1][1]=map[1][1];
for(int i=2;i<=m;i++) {dp[1][i]=map[1][i]+dp[1][i-1];}
for(int j=2;j<=n;j++) {dp[j][1]=map[j][1]+dp[j-1][1];}
/* for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
System.out.print(dp[i][j]+" ");
}
System.out.println();
}*/
for(int i=2;i<=n;i++) {
for(int j=2;j<=m;j++) {
dp[i][j]=Math.min(dp[i-1][j-1], Math.min(dp[i][j-1], dp[i-1][j]))+map[i][j];
}
}
System.out.println(dp[n][m]);
}
}
}
尼科彻斯定理
代码:
import java.util.Scanner;
public class Main {
static void print_(int m,int i,boolean flag){
if(flag==true){
for(int k=0;k<m;k++){
System.out.print(i+2*k);
if(k<m-1) System.out.print("+");
}
}
else System.out.print("-1");
}
public static void solve(int m) {
boolean flag=false;
int sum0=m*m*m;
int sum1=0,start;
for(int i=1;i<=sum0;i+=2){
sum1=0;
start=i;
for(int j=0;j<m;j++){
sum1=sum1+start;
start+=2;
}
if(sum1==sum0) {
flag=true;
print_(m,i,flag);
return;
}
}
flag=false;
print_(m,0,false);
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
int n=cin.nextInt();
solve(n);
System.out.println();
}
}
}
DNA序列
5思路:
代码:
import java.util.Scanner;
public class Main {
public static int solve(String str,int n) {
int i,j;
int count;
int max=0;
int index=0;
for(i=0;i+n<str.length();i++) {
count=0;
for(j=0;j<n;j++) {
if(str.charAt(i+j)=='G'||str.charAt(i+j)=='C')
count++;
}
if(count>max) {
max=count;
index=i;
}
}
return index;
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
int start;
String str=cin.next();
int n=cin.nextInt();
if(str.length()==0||n<=0||n>str.length()) {
return ;
}else {
start=solve(str,n);
for(int i=0;i<n;i++) {
System.out.print(str.charAt(start+i));
}
}
}
}
}
问题 F: 隔离14天
现在假定编号为0的乘客冠状病毒核酸检验呈阳性,请编写一个程序统计需隔离的总人数(包括编号为0的乘客)。
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2思路:
代码:
import java.util.Scanner;
public class Main {
static int pa[]=new int[1000];
static int rank[]=new int[1000];
public static void make_set(int x) {
pa[x]=x;
}//初始化
public static int find_set(int x) {
if(x!=pa[x]) {
pa[x]=find_set(pa[x]);
}
return pa[x];
}//查找
public static void union_set(int x,int y) {
x=find_set(x);
y=find_set(y);
if(x<y)pa[y]=x;
else pa[x]=y;
}//按秩合并x,y所在的集合
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n=cin.nextInt();
int m=cin.nextInt();//车辆
int head=0;
int x=0;
for(int i=1;i<=n;i++) {make_set(i);}
for (int i=1;i<=m;i++)
{
int k=cin.nextInt();
if (k>=1) head=cin.nextInt();
for (int j=2;j<=k;j++)
{
x=cin.nextInt();
union_set(x,head);//连接
}
}
int count=0;
for(int i=0;i<n;i++) {
if(find_set(i)==0)count++;
}
System.out.println(count);
}
}
问题 H: 单源最短路径问题
0 1 10
0 3 30
0 4 100
1 2 50
2 4 10
3 2 20
3 4 60代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int[][] graph=new int[1000][1000];
int d=cin.nextInt();//dian
int b=cin.nextInt();//bian
int[] dis=new int[d];
boolean[] visited=new boolean[d];
for(int i=0;i<d;i++) {
visited[i]=false;
}
visited[0]=true;
for(int i=0;i<d;i++) {
for(int j=0;j<d;j++) {
graph[i][j]=99999;
}
}
for(int i=1;i<=b;i++) {
int x=cin.nextInt();
int y=cin.nextInt();
graph[x][y]=cin.nextInt();
graph[y][x]=graph[x][y];
}
for(int i=0;i<d;i++) {
graph[i][i]=0;
}
dijkstra(graph, visited, dis,d);
for(int i=0;i<dis.length;i++)
System.out.print(dis[i]+" ");
}
static int maxint=99999;
public static void dijkstra(int map[][],boolean used[],int dis[],int n){
for(int i=0;i<n;i++) //初始化距离数组
dis[i] = map[0][i];
int k=0;
for(int i=1;i<n;i++){
int tmin = maxint;
//找出未访问点中距离值最小的点k,标记其为访问过
for(int j=1;j<n;j++)
if( !used[j] && dis[j] < tmin){
tmin = dis[j];
k = j;
}
used[k] = true;
for(int j=1;j<n;j++)
//对找出的点的相邻边进行松弛操作
if(!used[j]&&(dis[k] + map[k][j] < dis[j]))
dis[j] = dis[k] + map[k][j];
}
}
}