多多路上从左到右有N棵树(编号1~N),其中第i个颗树有和谐值Ai。
多多鸡认为,如果一段连续的树,它们的和谐值之和可以被M整除,那么这个区间整体看起来就是和谐的。现在多多鸡想请你帮忙计算一下,满足和谐条件的区间的数量。
第一行,有2个整数N和M,表示树的数量以及计算和谐值的参数。
( 1 <= N <= 100,000, 1 <= M <= 100 )
第二行,有N个整数Ai, 分别表示第i个颗树的和谐值。
( 0 <= Ai <= 1,000,000,000 )
共1行,每行1个整数,表示满足整体是和谐的区间的数量。
5 2 1 2 3 4 5
6
长度为1: [2], [4]
长度为2: 无
长度为3: [1,2,3], [3,4,5]
长度为4: [1,2,3,4], [2,3,4,5]
长度为5: 无
共6个区间的和谐值之和可以被2整除。
对于50%的数据,有N<=1,000对于100%的数据,有N<=100,000
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] params = br.readLine().split(" "); int n = Integer.parseInt(params[0]); int m = Integer.parseInt(params[1]); int[] map = new int[m]; // 除以m的余数为0~m-1 params = br.readLine().split(" "); int[] A = new int[n]; map[0] = 1; long culSum = 0L; long count = 0L; for(int i = 0; i < n; i++) { A[i] = Integer.parseInt(params[i]); culSum += A[i]; int remain = (int)(culSum % m); count += map[remain]; map[remain] ++; } System.out.println(count); } }
#include <iostream> #include <cstring> using namespace std; int main(){ int n, m; cin>>n>>m; int arr[n]; for (int i = 0; i < n; ++i){ cin>>arr[i]; } int map[m];//下标表示前缀和 % m后的值,map[i]表示取余后值为i的个数; memset(map, 0, sizeof(map)); map[0] = 1;//需要设置这个初始值,看下面代码就懂了 long sum = 0; long ans = 0; for (int i = 0; i < n; ++i){ sum += arr[i]; int index = sum % m; ans += map[index]++; } cout<<ans<<endl; return 0; }
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int M = sc.nextInt(); int[] ais = new int[N]; int[] sums = new int[N+1]; for(int i=0;i<N;i++){ ais[i] = sc.nextInt(); sums[i+1] = (sums[i]+ais[i])%M; } Map<Integer,Long> map = new HashMap<>(); for(int i=0;i<=N;i++){ int local = sums[i]%M; map.put(local,map.getOrDefault(local,0l)+1l); } long res = 0; for(long val:map.values()){ res += val*(val-1)/2; } System.out.println(res); } }
#include <bits/stdc++.h> typedef long long ll; using namespace std; ll n,m,a,sum=0,v[1005],ans; int main() { ios::sync_with_stdio(0),cin.tie(0); int i,j; cin>>n>>m; v[0]=1;/**< 用v数组统计每个位置前缀和余数的个数,相同余数的区间必然能被m整除 */ for(i=1;i<=n;i++) { cin>>a; sum=(sum+a)%m; v[sum]++; } for(i=0;i<m;i++)/**< 相同余数任选2个都可以和谐区间 */ ans+=v[i]*(v[i]-1)/2; cout<<ans; return 0; }
#include <iostream> #include <vector> using namespace std; int main() { long long n, m; cin >> n >> m; vector<long long> cnt(m, 0); //前缀和余数出现的次数 cnt[0] = 1; // 数值未加入前,前缀和为0,统计起点为0的情况 //前缀和sum[j] - sum[i]为区间[i, j]的总和 //所以统计前缀和余数相同的数出现的次数,任意选两个可以组成一个和谐区间 long long tree; long long sum = 0; for(int i = 0; i < n; i ++){ cin >> tree; tree = tree % m; sum = (sum + tree) % m; cnt[sum] ++; } long long ans = 0; for(int i = 0; i < m; i ++){ ans += cnt[i] * (cnt[i] - 1)/2; } cout << ans << endl; return 0; }
private static int f(int[] arr,int mod){ int n = arr.length,count=0; //c代表区间长度 for(int c=1;c<=n;c++){ //区间开始结束值以及区间和的大小 int end=0,start=0; long sum=0; while (end<c-1){ sum+=arr[end++]; } //从左到右“滑动区间”并计算是否满足条件 while (end<n){ sum+=arr[end++]; if(sum%mod==0){ count++; } sum-=arr[start++]; } } return count; }
private static int f(int[] arr,int mod){ long[] prefix=new long[arr.length+1]; int k=1; for(int i : arr){ prefix[k]=prefix[k-1]+i; k++; } int n = arr.length,count=0; for(int c=1;c<=n;c++){ int start=0; int end = start+c-1; if(end<n){ while(end<n){ if((prefix[end+1]-prefix[start])%mod==0){ count++; } start++;end++; } }else { break; } } return count; }
private static long f(int[] arr,int mod){ long[] prefix=new long[arr.length]; prefix[0]=arr[0]; Map<Long,Long> map = new HashMap<>(); map.put(prefix[0]%mod,1L); for(int i=1;i<arr.length;i++){ prefix[i]=prefix[i-1]+arr[i]; map.put(prefix[i]%mod,map.getOrDefault(prefix[i]%mod,0L)+1); } return map.values().stream().mapToLong(n->n*(n-1)/2).sum() +map.getOrDefault(0L,0L); //需要加上单值区间直接可以mod到0的情况 }
# 利用前缀和原理 n,m = list(map(int, input().strip().split(' '))) # 主要在意M就行,要能被M整除 ai=list(map(int,input().strip().split(' '))) # 每个数组的值 li={0:1} # li字典放所有的前缀和 除 m 得到的余数出现的次数,初始化我们需要 使出现 余数为 0 出现一次 sum=0 count = 0 # 用来统计 for i in ai: sum+= i # 前缀和 yu=sum%m # 求前缀和的除m的余数 if yu in li.keys(): # 如果 已有存在的key(余数)说明到他这里我们必有可以除断的。(可以理解为余数一样的那么中间这一段必定可以除断) # 然后我们需要看几个余数一样的来判断可以组合几个 count += li[yu] if yu not in li.keys(): # 将前缀和的余数存进字典 li[yu]=1 else: li[yu]+=1 print(count)
import java.util.*; public class Main{ public static void main(String[] args){ Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int M = scanner.nextInt(); int[] A = new int[N]; for(int i = 0; i < N; i++){ A[i] = scanner.nextInt(); } int count = 0; int sum = 0; Map<Integer, Integer> record = new HashMap<>(); //遍历数组nums之前,record提前放入 0:1 键值对,代表求第 0 项前缀和之前,前缀和 mod K 等于 0 这种情况出现了 1 次。 record.put(0,1); for(int elem : A){ sum+=elem;//前缀和 int model = (sum % M + M) % M;//取余数 //getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值0。 record.put(model, record.getOrDefault(model, 0)+1); } //values() 方法返回映射中所有 value 组成的 Set 视图 for(int n : record.values()){ count+=n*(n-1)/2; } //for(Map.Entry<Integer, Integer> entry : record.entrySet()){ // count+=entry.getValue()*(entry.getValue()-1)/2; //} System.out.println(count); } }
var firstline=readline().split(" ") var listlen=parseInt(firstline[0]) var harmonum=parseInt(firstline[1]) var list=readline().split(" ") var lista=list.map(item=>parseInt(item)) //存放0-i位置的数组和的余数 var leftnum=[] var sumtmp=0 var ans=0 //存放某个余数的出现个数 var map=new Map([[0,0]]) for(var i=0;i<listlen;i++){ sumtmp+=lista[i] if(sumtmp%harmonum==0){ans+=1} if(!map.has(sumtmp%harmonum)){ map.set(sumtmp%harmonum,1) }else{ ans+=map.get(sumtmp%harmonum) map.set(sumtmp%harmonum,map.get(sumtmp%harmonum)+1) } } console.log(ans)js版本
n,m = list(map(int, input().strip().split(' '))) ai=list(map(int,input().strip().split(' '))) li={} sum=0 for i in ai: sum+=i yu=sum%m if yu not in li.keys(): li[yu]=1 else: li[yu]+=1 hh=0 for i,j in li.items(): if i==0: hh+=j nn=j*(j-1)//2 hh+=nn print(hh)
import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static long countHarmonySubarrays(long[] A, int M) { long count = 0; long[] P = new long[A.length + 1]; Map<Long, Long> map = new HashMap<>(); for (int i = 0; i < A.length; i++) { P[i + 1] = P[i] + A[i]; if (P[i + 1] % M == 0) { count++; } if (map.containsKey(P[i + 1] % M)) { count += map.get(P[i + 1] % M); } if (!map.containsKey(P[i + 1] % M)) { map.put(P[i + 1] % M, 0L); } map.put(P[i + 1] % M, map.get(P[i + 1] % M) + 1); } return count; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int M = scanner.nextInt(); long[] A = new long[N]; for (int i = 0; i < N; i++) { A[i] = scanner.nextLong(); } System.out.println(countHarmonySubarrays(A, M)); } }
const rl = require("readline").createInterface({ input: process.stdin }); var iter = rl[Symbol.asyncIterator](); const readline = async () => (await iter.next()).value; // 相同余数的前缀区间任选两个所构成的中间区间一定和谐(因为大的那个前缀区间求和减去小的前缀区间求和,刚好把那个多出来的余数减掉了,因此中间区间求和一定能被m整除) void async function () { // Write your code here var arr=[]; while(line = await readline()){ arr.push(line) } // console.log("arr:",arr) var firstline=arr[0].split(" ") // console.log("firstline:",firstline) var listlen=parseInt(firstline[0]) var harmonum=parseInt(firstline[1]) var list=arr[1].split(" ") var lista=list.map(item=>parseInt(item)) // console.log('lista:',lista) // //存放0-i位置的数组和的余数 // var leftnum=[] var sumtmp=0 var ans=0 // //存放某个余数的出现个数 var map=new Map([[0,0]]) for(var i=0;i<listlen;i++){ sumtmp+=lista[i] if(sumtmp%harmonum==0){ans+=1} if(!map.has(sumtmp%harmonum)){ map.set(sumtmp%harmonum,1) }else{ ans+=map.get(sumtmp%harmonum) map.set(sumtmp%harmonum,map.get(sumtmp%harmonum)+1) } } console.log(ans) }()
#include<bits/stdc++.h> using namespace std; int main(){ long int n = 0, m = 0; cin>>n>>m; vector<long int> vec(n); for(auto &i : vec) cin>>i; vector<long int> arr(m, 0); long long int ans = 0; for(auto i : vec){ vector<long int> old = arr; for(int j = 0;j < m;j++){ arr[(i + j)%m] = old[j]; } arr[i%m]++; ans += arr[0]; } cout<<ans; return 0; }
#include <iostream> #include<vector> using namespace std; int main() { int N, M; cin >> N >> M; vector <int> arr(N); for (int i = 0; i < N; i++) { cin >> arr[i]; } vector <int> map(M,0); map[0] = 1; long sum = 0; long ans = 0; for(int i = 0; i < N; i++) { sum += arr[i]; int index = sum % M; ans += map[index]++; } cout << ans << endl; system("pause"); return 0; }
dp[i]: 以i结尾的满足条件的连续子数组数量 trees[]:树的和谐值
// 动态规划 import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); while (in.hasNextLine()) { String[] s1 = in.nextLine().trim().split(" "); String[] s2 = in.nextLine().trim().split(" "); int N = Integer.parseInt(s1[0]); int M = Integer.parseInt(s1[1]); int[] trees = new int[s2.length]; for (int i = 0; i < s2.length; i++) { trees[i] = Integer.parseInt(s2[i]); } long ans = solution(N, M, trees); System.out.println(ans); } } private static long solution(int N, int M, int[] trees) { // dp[i]: 以i结尾的满足条件的连续子数组数量 int[] dp = new int[N]; // 初始化 if (trees[0] % M == 0) { dp[0] = 1; } // 递推 long ans = dp[0]; for (int i = 1; i < N; i++) { // 递推公式 if (trees[i] % M == 0) { dp[i] = dp[i-1] + 1; } else { long sumVal = trees[i]; for (int j = i-1; j >= 0; j--) { sumVal += trees[j]; if (sumVal % M == 0) { if (j-1 < 0) { dp[i] = 1; } else { dp[i] = dp[j-1] + 1; } break; } } } ans += dp[i]; } return ans; } }
#include <iostream> #include <algorithm> #include <vector> #include <unordered_map> // #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int w[N]; unordered_map<int, int> cnt; void solve(){ cnt[0] = 1; int n, m; cin >> n >> m; int s = 0; long long ans = 0; for (int i = 1; i <= n; i ++ ) { int x; cin >> x; s = (s + x) % m; ans += cnt[s]; cnt[s] ++ ; } cout << ans << endl; } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int t; // cin >> t; t = 1; while (t -- ) solve(); return 0; }