待办:
BaseOn : https://www.acwing.com
in.next()
和in.nextLine()
package com.caopeng.zero;
import java.util.Scanner;
/**
* @author Crescent_P
* @date 2021-12-02 19:41
*/
public class InputOutput1 {
public static void main(String[] args) {
// Scanner类输入
Scanner in = new Scanner(System.in);
// 整数
// int a = in.nextInt();
// 浮点数
// double v = in.nextDouble();
// 长整数
// long c = in.nextLong();
// short
// short d = in.nextShort();
// 字符串
String s1 = in.next(); // c++ 中的 cin/scanf 遇到空格结束
String s2 = in.nextLine(); // c++ 中的 gets 遇到回车结束
// 输入 abc def g
System.out.println("s1 :" + s1); // s1 :abc
System.out.println("s2 :" + s2); // s2 : def g
}
}
hasNext()
package com.caopeng.zero;
import java.util.Scanner;
/**
* @author Crescent_P
* @date 2021-12-02 19:41
*/
public class InputOutput2 {
public static void main(String[] args) {
// Scanner类输入
Scanner in = new Scanner(System.in);
// hasNext()
// hasNext()返回的是bool类型、当缓冲区有数据返回true
// 当缓冲区没有数据会发生阻塞、等待数据的输入
// 遇到多组输入,不知道什么时候能结束输入可以使用
// while(in.hasNext()) 相当于 while(scanf())
int a,b,c;
while(in.hasNext()){
a = in.nextInt();
b = in.nextInt();
c = in.nextInt();
System.out.printf("%d\n",a+b+c); // 模式化输出
}
}
}
// 常见的输出
System.out.println(); // 带换行的
System.out.print(); // 不带换行的
System.out.printf(); // 格式化输出,相当于c/c++ 的 printf
BufferedReader
和BufferedWriter
实现
java
import java.util.*;
public class Main{
static Scanner in = new Scanner(System.in); // 输入
// 看题目范围 n是1到15,我们稍微把数组开大一点点、防止数组越界。
static int max = 20,n;
// 判断每一位是否被用过
static boolean[] st = new boolean[max];
public static void main(String[] args){
n = in.nextInt();
dfs(0);
}
// dfs(深度优先搜索)
private static void dfs(int u){
// 搜索到最后一位
if(u == n){
// 打印输出
for(int i = 0;i < n;i++){
if(st[i]) System.out.printf("%d ",i+1);
}
System.out.println();
return;
}
// 要第u位
st[u] = true;
dfs(u+1);
// 不要第u位
st[u] = false;
dfs(u+1);
}
}
C/C++
#include
using namespace std;
const int N = 20;
bool st[N];
int n;
void dfs(int u){
// 递归到了叶子节点
if(u == n){
for(int i = 0;i < n;i++){
if(st[i]) cout << i + 1 << " ";
}
cout << endl; // 换行
return;
}
// 选
st[u] = true;
dfs(u+1);
// 不选
st[u] = false;
dfs(u+1);
}
int main(){
cin >> n;
dfs(0);
return 0;
}
Java
import java.util.*;
import java.io.*;
public class Main {
static Scanner in = new Scanner(System.in);
static int max = 10, n;
static int[] path = new int[max]; // 存储路径
static boolean[] st = new boolean[max]; // 记录每个数字是否被使用了
static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args)throws Exception{
n = in.nextInt();
dfs(0);
out.flush();
}
private static void dfs(int u) throws Exception{
if(u == n){
for(int i = 0;i < n;i++) out.write(path[i] + " "); // 快速写出
out.write("\n"); // 换行
return;
}
for(int i = 0;i < n;i++){
if(!st[i]){
st[i] = true;
path[u] = i+1;
dfs(u+1);
st[i] = false;
path[u] = 0;
}
}
}
}
C/C++
#include
using namespace std;
const int N = 10;
int path[N];
bool st[N];
int n;
void dfs(int u){
if(u == n){
for(int i = 0;i < n;i++) cout << path[i] << " ";
cout << endl;
return;
}
for(int i = 0;i < n;i++){
if(!st[i]){
st[i] = true;
path[u] = i+1;
dfs(u+1);
st[i] = false;
}
}
}
int main(){
cin >> n;
dfs(0);
return 0;
}
Java
import java.util.*;
public class Main{
static Scanner in = new Scanner(System.in);
static int max = 30,n,m;
static int[] path = new int[max];
public static void main(String[] args){
n = in.nextInt();
m = in.nextInt();
dfs(0);
return;
}
public static void dfs(int u){
if(u == m){
for(int i = 0;i < m;i++) System.out.printf("%d ",path[i]);
System.out.println();
return;
}
for(int i = 1;i <= n;i++){
if(u == 0) path[u] = i;
else {
if(path[u-1] < i) path[u] = i;
else continue;
}
dfs(u+1);
}
}
}
C/C++
#include
using namespace std;
const int N = 30;
int path[N];
int n,m;
void dfs(int u){
if(u == m){
for(int i = 0;i < m;i++) cout << path[i] << " ";
cout << endl;
return;
}
for(int i = 1;i <= n;i++){
if(u == 0) path[u] = i;
else{
// 前一位要比这一位小
if(path[u-1] < i) path[u] = i;
else continue;
}
dfs(u+1);
}
}
int main(){
cin >> n >> m;
dfs(0);
return 0;
}
java
import java.util.*;
public class Main{
static Scanner in = new Scanner(System.in);
static int n,a = 0,b = 1;
public static void main(String[] args){
n = in.nextInt();
for(int i = 0;i < n;i++){
System.out.printf("%d ",a);
int temp = a + b;
a = b;
b = temp;
}
}
}
C/C++
#include
using namespace std;
// 递推公式
// a[i] = a[i-1] + a[i-2]
int n;
int main(){
int a = 0,b = 1;
cin >> n;
for(int i = 0;i < n;i++){
cout << a << " ";
int temp = a + b;
b = a;
a = temp;
}
cout << endl;
return 0;
}
想写出这个题目,首先得分析出几个点:
依靠上面两个结论,我们来看这一题:
因此:
C/C++
#include
using namespace std;
const int N = 6;
char g[N][N],backup[N][N];
// 偏移量,用于遍历(x,y)的上下左右中
int dx[5] = {1,0,-1,0,0},dy[5] = {0,1,0,-1,0};
// 将(x,y)的上下左右摁一遍
void turn(int x,int y){
for(int i = 0;i < 5;i++){
int nx = x + dx[i],ny = y + dy[i];
if(nx < 0 || nx > 5 || ny < 0 || ny > 5) continue; // 外界不需要考虑
if(g[nx][ny] == '0') g[nx][ny] = '1';
else g[nx][ny] = '0';
}
}
int main(){
int T;
cin >> T;
while(T--){
// 将图读入
for(int i = 0;i < 5;i++) cin >> g[i];
// 第一行一共5个按钮,每个按钮开或不开一共2种情况,2^5 = 32
int ans = 10;
for(int op = 0;op < 32;op++){
memcpy(backup,g,sizeof g); // 将 g的内容放入backup中备份
int step = 0; // 操作的步数
// 第一行所有情况
for(int i = 0;i < 5;i++){
// 当前对应了1就操作
if(op >> i & 1){
step++;
turn(0,i);
}
}
// 每一行的每一个开关开或不开其实是受上一行的开关影响的
for(int i = 0;i < 4;i++){
for(int j = 0;j < 5;j++){
// 当前是关的,那么下一行对应的必须操作一次,这个才能打开
if(g[i][j] == '0'){
step++;
turn(i+1,j);
}
}
}
// 最后一行是不能有关闭的,否则就是不能实现
bool dark = false;
for(int i = 0;i < 5;i++){
if(g[4][i] == '0'){
dark = true;
break;
}
}
if(!dark) ans = min(ans,step);
memcpy(g,backup,sizeof g); // 将 g的内容放入backup中备份
}
if(ans > 6) ans = -1;
cout << ans << endl;
}
return 0;
}
java
import java.util.*;
public class Main{
static Scanner in = new Scanner(System.in);
static int max = 5;
static char[][] g = new char[max][max];
static char[][] backup = new char[max][max];
static int[] dx = {1,0,-1,0,0},dy = {0,1,0,-1,0};
public static void main(String[] args){
int T = in.nextInt();
// T个测试样例
while(T-- > 0){
// 读入图
int res = 10;
for(int i = 0;i < 5;i++) g[i] = in.next().toCharArray();
// 要对图进行一次备份
for(int i = 0;i < 5;i++){
for(int j = 0;j < 5;j++) backup[i][j] = g[i][j];
}
// 第一行有5个格子,每个格子开或关有2种可能,一共2^5=32种,我们这里采用二进制来表示
for(int op = 0;op < 32;op++){
int step = 0;
// 先操作第一行
for(int i = 0;i < 5;i++){
// 当前位是1就进行一次操作
if((op >> i & 1) == 1){
turn(0,i);
step++;
}
}
// 通过上一行操作下一行
for(int i = 0;i < 4;i++){
for(int j = 0;j < 5;j++){
// 当前是灭的,那么下一行对应的就要开
if(g[i][j] == '0'){
turn(i+1,j);
step++;
}
}
}
// 判断最后一行有没有灭的
boolean dark = false;
for(int i = 0;i < 5;i++){
if(g[4][i] == '0'){
dark = true;
break;
}
}
// 全灭的话
if(!dark) res = Math.min(res,step);
// 对图进行还原
for(int i = 0;i < 5;i++){
for(int j = 0;j < 5;j++) g[i][j] = backup[i][j];
}
}
// 超过步数
if(res > 6) res = -1;
// 此时已经遍历了32种情况
System.out.println(res);
}
}
public static void turn(int x,int y){
for(int i = 0;i < 5;i++){
int nx = x + dx[i],ny = y + dy[i];
if(nx < 0 || nx >= 5 || ny < 0 || ny >= 5) continue; // 出界不需要考虑
if(g[nx][ny] == '0') g[nx][ny] = '1';
else g[nx][ny] = '0';
}
}
}
按照之前的思考:
对于此题:
我们可以就从左到右枚举,当前对应位不一样,就翻转一下即可。
c/c++
#include
using namespace std;
string a,b;
int ans = 0;
int main(){
cin >> a >> b;
int n = a.length();
for(int i = 0;i < n - 1;i++){
// 当前字符不相等,就要翻转,
// 翻转后一定相等,就不用判断了
// 但是只要翻转了,下一个字符就一定会改
if(a[i] != b[i]){
ans++;
if(a[i+1] == '*') a[i+1] = 'o';
else a[i+1] = '*';
}
}
cout << ans << endl;
}
Java
import java.util.*;
import java.io.*;
public class Main{
static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
static int N = 110;
static char[] begin = new char[N],end = new char[N];
public static void main(String[] args)throws Exception{
int ans = 0;
// 读入
String a = in.readLine();
String b = in.readLine();
begin = a.toCharArray();
end = b.toCharArray();
for(int i = 0;i < begin.length-1;i++){
if(begin[i] != end[i]){
if(begin[i+1] == '*') begin[i+1] = 'o';
else begin[i+1] = '*';
ans++;
}
}
in.close();
System.out.println(ans);
}
}
C/C++
#include
#define x first
#define y second
using namespace std;
typedef pair PII;
const int N = 5;
char g[N][N],backup[N][N];
// 将二维映射成一维
int get(int x,int y){
return x*4 + y;
}
void turn_one(int x,int y){
if(g[x][y] == '-') g[x][y] = '+';
else g[x][y] = '-';
}
// 将x行,y列的所有操作一遍
void turn_all(int x,int y){
for(int i = 0;i < 4;i++){
turn_one(i,y);
turn_one(x,i);
}
// 上面导致(x,y)改变了两次,抵消了
turn_one(x,y);
}
int main(){
// 读入图
for(int i = 0;i < 5;i++) cin >> g[i];
vector ans;
// 枚举所有的情况
for(int op = 0;op < 1 << 16;op++){
memcpy(backup,g,sizeof g); // 备份
// 这一种情况的操作
vector temp;
// 对每一个点继续操作
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
// 点是二维的,我们映射成一维好操作
if(op >> get(i,j) & 1){
temp.push_back({i,j}); // 将操作入队列
turn_all(i,j);
}
}
}
// 判断是否全开的
bool has_closed = false;
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
if(g[i][j] == '+') has_closed = true;
}
}
// 全是开的
if(!has_closed){
// ans为空或者ans的操作步骤比temp多
if(ans.empty() || ans.size() > temp.size()) ans = temp;
}
memcpy(g,backup,sizeof g); // 还原
}
// 输出
cout << ans.size() << endl;
for(auto op : ans){
cout << op.x + 1 << " " << op.y+1 << endl;
}
return 0;
}
Java
import java.util.*;
public class Main{
static int N = 4;
static char[][] g = new char[N][N],backup = new char[N][N];
static Scanner in = new Scanner(System.in);
static List<int[]> ans = new ArrayList<>();
public static void main(String[] args){
// 把图给读进来
for(int i = 0;i < 4;i++) g[i] = in.next().toCharArray();
// 一共16个开关,全部枚举,2^16
for(int op = 0;op < (1 << 16);op++){
List<int[]> temp = new ArrayList<>();
// 备份图
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
backup[i][j] = g[i][j];
}
}
// 遍历每一个点
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
// 为1就是要操作
if(((op >> get(i,j)) & 1) == 1){
turn_all(i,j);
temp.add(new int[]{i,j});
}
}
}
// 此时遍历完了,看是否全打开了
boolean has_closed = false;
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
if(g[i][j] == '+') has_closed = true;
}
}
// 没有关闭的
if(!has_closed){
if(ans.isEmpty() || ans.size() > temp.size() ) ans = temp;
}
// 复原
for(int i = 0;i < 4;i++){
for(int j = 0;j < 4;j++){
g[i][j] = backup[i][j];
}
}
}
System.out.println(ans.size());
for(int[] res : ans){
System.out.printf("%d %d\n",res[0]+1,res[1]+1);
}
}
public static int get(int x,int y){
return 4 * x + y;
}
public static void turn_all(int x,int y){
for(int i = 0;i < 4;i++){
turn_one(x,i);
turn_one(i,y);
}
turn_one(x,y);
}
public static void turn_one(int x,int y){
if(g[x][y] == '-') g[x][y] = '+';
else g[x][y] = '-';
}
}
思路一:
C/C++
#include
using namespace std;
const int N = 10;
int path[N];
bool st[N];
int n,ans = 0;
// 计算path[l,r]的位数和
int cala(int l,int r){
int sum = 0;
for(int i = l; i <= r;i++){
sum *= 10;
sum += path[i];
}
return sum;
}
void dfs(int u){
if(u == N){
// 此时path中存了1~9的全排列
for(int i = 1;i <= 7;i++){
for(int j = i+1;j <= 8;j++){
int a = cala(1,i);
int b = cala(i+1,j);
int c = cala(j+1,9);
if(n*c == a * c + b) ans++;
}
}
}
for(int i = 1;i < N;i++){
if(!st[i]){
st[i] = true;
path[u] = i;
dfs(u+1);
st[i] = false;
}
}
}
int main(){
cin >> n;
dfs(1);
cout << ans << endl;
return 0;
}
JAVA
import java.util.*;
public class Main{
static int N = 10;
static int[] path = new int[N]; // 用于储存全排列
static boolean[] st = new boolean[N];
static Scanner in = new Scanner(System.in);
static int n,ans = 0;
public static void main(String[] args){
n = in.nextInt();
dfs(1);
System.out.println(ans);
}
private static void dfs(int u){
// 此时path以及存好了全排列
if(u == N){
for(int i = 1;i <= 7;i++){
for(int j = i+1;j <= 8;j++){
int a = cala(1,i);
int b = cala(i+1,j);
int c = cala(j+1,9);
if(n*c == a*c + b) ans++;
}
}
}
for(int i = 1;i < N ;i++){
if(!st[i]){
path[u] = i;
st[i] = true;
dfs(u+1);
st[i] = false;
}
}
}
public static int cala(int l,int r){
int sum = 0;
for(int i = l;i <= r;i++){
sum *= 10;
sum += path[i];
}
return sum;
}
}
思路二:
c/c++
#include
using namespace std;
const int N = 20;
bool st[N],backup[N];
int n,ans;
// 判断等式是否成立
bool check(int a,int c){
int b = n*c - a*c;
// a b c 都得是非0的
if(!a || !b || !c) return false;
// st表在递归中还要使用,使用备份表
memcpy(backup,st,sizeof st);
// 判断b的每一位有没有和a、c有重合的
while(b){
int x = b % 10;
b /= 10;
// 出现位0或者重复使用过
if(!x || backup[x]) return false;
backup[x] = true;
}
// 判断每一位是否都使用过了
for(int i = 1;i <= 9;i++){
if(!backup[i]) return false;
}
return true;
}
void dfs_c(int u,int a,int c){
if(u == 9) return;
if(check(a,c)) ans++;
for(int i = 1;i <=9;i++){
if(!st[i]){
st[i] = true;
dfs_c(u+1,a,c*10+i);
st[i] = false;
}
}
}
// 从第u位枚举,此时的a大小位a
void dfs_a(int u,int a){
// 第10位
if(u == 9) return;
// 剪枝,因为 n = a + b/c 所有a肯定小于n
if(a > n) return;
// 递归枚举c
if(a) dfs_c(u,a,0);
for(int i = 1;i <= 9;i++){
if(!st[i]){
st[i] = true;
dfs_a(u+1,a*10+i);
st[i] = false;
}
}
}
int main(){
cin >> n;
dfs_a(0,0);
cout << ans << endl;
return 0;
}
Java
import java.util.*;
public class Main{
static int N = 10;
static boolean[] st = new boolean[N]; // 每一位只能使用一次
static Scanner in = new Scanner(System.in);
static int n,ans = 0;
public static void main(String[] args){
n = in.nextInt();
// 从1开始搜索,此时a为0
dfs_a(1,0);
System.out.println(ans);
}
private static void dfs_a(int u,int a){
// 第十位
if(u == N) return;
// 剪枝,a不可能大于n
if(a > n) return;
// 递归遍历c
if(a > 0) dfs_c(u,a,0);
for(int i = 1;i < N;i++){
if(!st[i]){
st[i] = true;
// 递归a
dfs_a(u+1,a*10+i);
st[i] = false;
}
}
}
private static void dfs_c(int u,int a,int c){
if(u == N) return;
// 判断此时的ac是否满足条件
if(check(a,c)) ans++;
for(int i = 1;i < N;i++){
if(!st[i]){
st[i] = true;
// 递归c
dfs_c(u+1,a,c*10+i);
st[i] = false;
}
}
}
// 判断是否满足条件
private static boolean check(int a,int c){
int b = n * c - a * c;
// a b c 都是正数
if(b <= 0 || a <= 0 || c <= 0) return false;
// 判断是否有重复使用的数
boolean[] backup = new boolean[N];
// 使用备份来判断
for(int i = 1;i < N;i++) backup[i] = st[i];
while(b > 0){
int x = b %10;
b /= 10;
if(x == 0 || backup[x]) return false;
backup[x] = true;
}
// 判断1~9是否每一位都使用过
for(int i = 1;i < N;i++){
if(!backup[i]) return false;
}
return true;
}
}
C/C++
#include
using namespace std;
const int N = 1e5 + 10;
int n,q;
int a[N];
int main(){
cin >> n >> q;
for(int i = 0;i < n;i++) cin >> a[i];
while(q--){
int k;
cin >> k;
// 边界
int l = 0,r = n-1;
// 找到第一个大于等于k的数
while(l < r){
// 枚举范围内的中点
int mid = (l + r) >> 1;
if(a[mid] >= k) r = mid;
else l = mid + 1;
}
// 可以发现,从上面的循环跳出来的时候 l = r
// 如果二分的结果不为k,表示没有这个数,输出-1 -1 即可
if(a[l] != k){
cout << "-1 -1" << endl;
continue;
}
// 运行到这里就是能找到这个数
cout << l << " ";
l = 0,r = n-1;
while(l < r){
int mid = (l+r+1) >> 1;
if(a[mid] <= k) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
return 0;
}
Java
C/C++
#include
using namespace std;
const int N = 1e5 + 10;
int n;
int h[N];
bool check(int mid){
// 模拟,走一遍
for(int i = 1;i <= n;i++){
mid = 2 * mid - h[i];
// 因为h[i] < 1e5,当中途的能量大于1e5的时候,就能直接确认一定能通过
if(mid >= 1e5) return true;
else if(mid < 0) return false;
}
return true;
}
int main(){
scanf("%d",&n);
for(int i = 1; i<= n;i++) scanf("%d",&h[i]);
int l = 0 ,r = 100000;
// 二分初始值
while(l < r){
int mid = (l + r) >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
JAVA
C/C++
#include
using namespace std;
const int N = 1e5 + 10;
typedef long long LL;
int h[N],w[N];
int n,k;
bool check(int mid){
LL res = 0;
for(int i = 0;i < n;i++){
res += (h[i] / mid) * (w[i] / mid);
// 满足条件
if(res >= k) return true;
}
return false;
}
int main(){
scanf("%d%d",&n,&k);
// 读入长、宽
for(int i = 0;i < n;i++) scanf("%d%d",&h[i],&w[i]);
int l = 1,r = 1e5;
// 二分边长
while(l < r){
int mid = (l + r + 1) >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n",l);
return 0;
}
这个就是浮点数二分问题
C/C++
#include
using namespace std;
int main(){
double n;
cin >> n;
// 看题目 n的数据范围 -10000 ~ 10000
double l = -10000,r = 10000;
// 精度是 小数点后六位,我们精确的8位一般就没问题
while(r-l > 1e-8){
double mid = (l + r) / 2;
if(mid * mid * mid > n) r = mid;
else l = mid;
}
printf("%lf",l);
return 0;
}
C\C++
暴力,能过一定的点,最终TLE
#include
using namespace std;
int n;
int main(){
scanf("%d",&n);
for(int a = 0;a*a <= n;a++){
for(int b = a;a*a+b*b <= n;b++){
for(int c = b;a*a+b*b+c*c<=n;c++){
int t = n - a*a - b*b - c*c;
int d = sqrt(t);
if(d * d == t){
printf("%d %d %d %d\n",a,b,c,d);
return 0;
}
}
}
}
return 0;
}
哈希
数据太强了、hash也卡
STL的哈希表
#include
using namespace std;
typedef pair<int,int> PII;
int n;
unordered_map<int,PII> m;
int main(){
scanf("%d",&n);
for(int c = 0;c * c <= n;c++){
for(int d = c;d*d + c*c <= n;d++){
int t = c*c + d*d;
if(m.count(t) == 0) m[t] = {c,d};
}
}
for(int a = 0; a*a <= n;a++){
for(int b = 0;b*b +a*a<= n;b++){
int sum = n - a*a - b*b;
if(m.count(sum)){
printf("%d %d %d %d\n",a,b,m[sum].first,m[sum].second);
return 0;
}
}
}
return 0;
}
手写哈希表可以过
#include
using namespace std;
typedef pair<int,int> PII;
int n;
const int N = 5000010;
int C[N],D[N];
int main(){
scanf("%d",&n);
// 初始化为-1
memset(C,-1,sizeof C);
for(int c = 0;c * c <= n;c++){
for(int d = c;d*d + c*c <= n;d++){
int s = c*c + d*d;
if(C[s] == -1){
C[s] = c,D[s] = d;
}
}
}
for(int a = 0; a*a <= n;a++){
for(int b = 0;b*b +a*a<= n;b++){
int s = n - a*a - b*b;
if(C[s] != -1){
printf("%d %d %d %d",a,b,C[s],D[s]);
return 0;
}
}
}
return 0;
}
C/C++
#include
using namespace std;
const int N = 1e5 + 10;
int a[N],s[N];
int n,m;
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
// 处理前缀和数组
s[i] = s[i-1] + a[i];
}
while(m--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",s[r] - s[l-1]);
}
return 0;
}
C/C++
#include
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int a[N];
LL sum[N],cnt[N];
int n,k;
int main(){
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
sum[i] += sum[i-1] + a[i]; // 前缀和数组
}
LL ans = 0;
// 余数为i的个数
cnt[0] = 1;
for(int i = 1;i <= n;i++){ // 枚举右端点
ans += cnt[sum[i] % k];
cnt[sum[i]%k]++;
}
printf("%lld",ans);
}
C/C++
#include
using namespace std;
const int N = 1010;
int a[N][N],s[N][N];
int n,m,q;
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++) {
scanf("%d",&a[i][j]);
s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
}
}
while(q--){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%d\n",s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
}
return 0;
}
Java
#include
using namespace std;
int main(){
int a,b;
cin >> a >> b;
cout << a * b - a - b << endl;
return 0;
}
#include
using namespace std;
const int N = 55;
int n;
int x[N];
int main(){
cin >> n;
for(int i = 0;i < n;i++) cin >> x[i];
// 左边向右走和右边向左走
int left = 0,right = 0;
for(int i = 0;i < n;i++){
// 右边向左走
if(abs(x[0]) > abs(x[i]) && x[i] > 0) left++;
else if(abs(x[0]) < abs(x[i]) && x[i] < 0) right++;
}
// 感冒蚂蚁向左走,并且没有左边蚂蚁向右走的 或者 感冒蚂蚁向右走,并且没有向右边左走的蚂蚁
if((x[0] > 0 && right == 0) || ( x[0] < 0 && left == 0)) cout << 1 << endl;
else cout << left + right + 1 << endl;
return 0;
}
#include
using namespace std;
int getDrink(int n){
// sum 喝的饮料数, count 瓶盖数
int sum = n,count = n;
while(count >= 3){
sum += count / 3; // 3个瓶盖兑换成一个瓶子
count = count / 3 + count % 3; // 剩余的盖子数量
}
return sum;
}
int main(){
int n;
scanf("%d",&n);
printf("%d",getDrink(n));
return 0;
}
#include
using namespace std;
const int N = 1010;
int weight[N],value[N];
int n,bag;
// 二维01背包
void m1();
// 一维01背包
void m2();
int main(){
scanf("%d%d",&n,&bag);
for(int i = 0;i < n;i++) scanf("%d%d",&weight[i],&value[i]);
// m1();
m2();
return 0;
}
// 二维dp
void m1(){
// dp[i][j] 在0~i件物品中任选、背包容量为j,能装下的最大价值为dp[i][j]
// 递推公式:
// 对于第i件物品来说,可以分为选和不选两个状态
// 不选第i件物品 dp[i][j] = dp[i-1][j]
// 选第i件物品 dp[i][j] = dp[i-1][j-weight[i]] + value[i]
// 那么dp[i][j]就是这两种情况中最大的
// 初始化
// 看递推公式 会用到dp[0][j] 和 dp[i][0]
// dp[0][j] 当能放入第0件物品的时候,dp[0][j] = value[0]
// dp[i][0] 容量为0,价值也为0,那么 dp[i][0] = 0
// 遍历顺序,从左上遍历到左下
vector<vector<int>> dp(n,vector<int>(bag+1,0));
// 初始化
// for(int i = 0;i < n;i++) dp[i][0] = 0; // 不用初始化也为0
for(int j = weight[0];j <= bag;j++) dp[0][j] = value[0];
// 状态转移
for(int i = 1;i < n;i++){ // 第0件物品已经初始化了,遍历物品
for(int j = 0;j <= bag;j++){ // 遍历背包
if(j < weight[i]) dp[i][j] = dp[i-1][j]; // 放不下,就不要第i件物品
else dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
}
}
printf("%d\n",dp[n-1][bag]);
}
// 一维dp
void m2(){
// dp[j] 容量为j,背包最大能装下dp[j]价值的物品
// 状态转移方程 和一维的一样,分为要第i件物品和不要第i件物品
// dp[j] = max(dp[j],dp[j-weight[i]]+value[i])
// 初始化
// dp[0] = 0
// 遍历顺序
// 一维dp其实是二维dp的压缩,就是当前这一行,复制拷贝了上面一行
// 二维dp遍历是从左上往右下遍历,就是对于一个dp[i][j]其实依赖于左上方的值
// 那么一维更新的时候,就不能覆盖到左边的值,应该用左边的值去更新右边的值
// 因此对于内层循环,应该从右往左
vector<int> dp (bag+1,0);
dp[0] = 0;
for(int i = 0;i < n;i++){
for(int j = bag;j >= weight[i];j--) dp[j] = max(dp[j],dp[j-weight[i]]+value[i]);
}
printf("%d\n",dp[bag]);
}
#include
using namespace std;
const int N = 110;
// dp[i][j] 到(i,j)位置采摘到的最多的花生
// 到(i,j)只有两种办法 (i-1,j)或者(i,j-1)
// 所以 dp[i][j] = max(dp[i-1][j],dp[i][j-1])+a[i][j]
// 可以看到需要用到 dp[i][0] 以及 dp[0][j]
// dp[i][0] 就是 第一列从上面走到下面 dp[0][j] 就是第一行,从左边走到右边
int a[N][N],dp[N][N];
int r,c,ans,T;
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&r,&c);
for(int i = 0;i < r;i++){
for(int j = 0;j < c;j++) scanf("%d",&a[i][j]);
}
dp[0][0] = a[0][0];
for(int i = 1;i < r;i++) dp[i][0] = a[i][0] + dp[i-1][0];
for(int j = 1;j < c;j++) dp[0][j] = a[0][j] + dp[0][j-1];
for(int i = 1;i < r;i++){
for(int j = 1;j < c;j++) dp[i][j] = max(dp[i-1][j],dp[i][j-1])+a[i][j];
}
printf("%d\n",dp[r-1][c-1]);
}
return 0;
}
#include
using namespace std;
const int N = 1010;
// dp[i] i以及i之前的最长上升子序列的长度为dp[i]
// if(a[i] > a[j] ) dp[i] = max(dp[i],dp[j]+1);
// dp[0] = 1
int a[N],dp[N];
int n,ans = 0;
int main(){
scanf("%d",&n);
// 读入数组
for(int i = 0;i < n;i++) scanf("%d",&a[i]);
for(int i = 0;i < n;i++) dp[i] = 1;
for(int i = 1;i < n;i++){
for(int j = 0;j < i;j++){
if(a[i] > a[j]) dp[i] = max(dp[i],dp[j]+1);
ans = max(dp[i],ans);
}
}
printf("%d\n",ans);
}