输入第一行两个数n , k
第二行n个数, a1 , a2 , a3……… , an
输出一个数,一共有多少台路由器可以收到至少k台不同路由器的信号。
4 4 3 3 3 3
4
#include<iostream>
(720)#include<stdio.h>
#define MaxN 100010
using namespace std;
int N, K;
int chafen[MaxN];//差分数组
int main(){
scanf("%d%d", &N, &K);
int temp;
for(int i=0; i<N; i++){
scanf("%d", &temp);
chafen[max(0, i-temp)]++; //最左发送范围
chafen[min(N, i+temp+1)]--; //最右发送范围的下一个路由器
}
int sum = 0, ans = 0;
for(int i=0; i<N; i++){
sum+=chafen[i]; //还原出原数组第i项
if(sum >= K)
ans++;
}
cout<<ans<<endl;
return 0;
} 看了这么多题解,根本没看懂,说一下我个人对这道题的理解。
首先python代码如下:
if __name__=='__main__':
n,k = list(map(int,input().split()))
num = list(map(int,input().split()))
res = []
for i in range(n):
l = max(0,i-num[i])
r = min(n,i+num[i]+1)
res.append((l,r))
dp = [0 for _ in range(n+1)]
for i in range(n):
dp[res[i][0]] += 1
dp[res[i][1]] -= 1
count = 0
temp = 0
for i in range(len(dp)):
temp += dp[i]
if temp >= k:
count += 1
print(count)上面主要使用了两个存储:
res 和 dp
res 的作用是记录每个路由器能到达的左边界。
res[i][0] = 0的话,表示路由器i最左边能到达坐标 0 。
也说明了能到达 坐标 1, 2, ... 。但是最右能到达哪呢?这个在res[i][1] 记录着。
dp数组累加表示坐标 i 有几个路由器能到达。
看下面dp怎么算的,大家就能理解这个算法奥秘了。
for i in range(n):
dp[res[i][0]] += 1
dp[res[i][1]] -= 1以
4 4
3 1 3 2 为例。
我把它的res dp 结果输出了。
('res = ', [(0, 4), (0, 3), (0, 4), (1, 4)])
('dp = ', [3, 1, 0, -1, -3])
这个方法还是很巧妙,有知道这种题是属于什么类型的,求告知,感谢!!!
public class Main {
public static void main(String[] args) {
java.util.Scanner sc = new java.util.Scanner(System.in);
int N = sc.nextInt(), K = sc.nextInt();
int[] delta = new int[N + 2];
for (int i = 1; i <= N; ++i) {
int r = sc.nextInt();
delta[Math.max(0, i - r)] += 1;
delta[Math.min(N + 1, i + r + 1)] -= 1;
}
int cnt = 0, sum = delta[0];
for (int i = 1; i <= N; ++i) {
sum += delta[i];
if (sum >= K) {
++cnt;
}
}
System.out.println(cnt);
}
}
恕我直言,没一个答案把此题的思路讲清楚,代码我就不贴了,大同小异。此题的的求解关键在于差分数组,不是什么dp。看不懂代码的同学强烈建议搜索差分数组,理解其原理性质后再读代码就很好理解了。
n, k = map(int, input().strip().split()) route = list(map(int, input().strip().split())) area = [] # 计算路由i的信号能到达的左右边界 for i in range(n): left = max(0, i - route[i]) # 路由i能到达的左边界 right = min(n, i + route[i] + 1) # 路由i能到达的右边界(第一个到达不了的路由) area.append((left, right)) """ 对于路由器i,它能发送的最左路由器b会比b左侧的路由器多收到一条来自i的信号; 它右侧发送不到的第一个路由器c会比c左侧的路由器少收到一条来自i的信号。 """ diff = [0]*(n + 1) for i in range(n): # 对于路由器i,用其作为左边界的次数-作为右边界的次数,就可以得到它比前一台路由多收到几条信号,即差分 diff[area[i][0]] += 1 diff[area[i][1]] -= 1 # 利用差分数组的前i项和就可以还原出原数组的第i项 count = 0 counter_i = 0 for i in range(n + 1): counter_i += diff[i] if counter_i >= k: count += 1 print(count)
#include <iostream>
(720)#include <bits/stdc++.h>
using namespace std;
//学习到了查分数组,进行复杂度为o(n)的遍历
int coverage(vector<int> num,int k)
{
int n=num.size();
vector<int> dp(n,0);
for(int i=0;i<n;i++)
{
dp[max(0,i-num[i])]+=1;
if(i+num[i]+1<n) dp[i+num[i]+1]-=1;
}
int res=0;
int cover=0;
for(int i=0;i<n;i++)
{
cover+=dp[i];
if(cover>=k) res++;
}
return res;
}
int main()
{
int N,k;
while(cin>>N>>k)
{
vector<int> strength(N,0);
for(int i=0;i<N;i++)
{
cin>>strength[i];
}
cout<<coverage(strength,k);
}
} #include <bits/stdc++.h>
using namespace std;
int main(){
int n,k;
cin>>n>>k;
int a[n+1],c[n+1];
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++){
cin>>a[i];
c[max(0,i-a[i])]++;
c[min(n+1,i+a[i]+1)]--;
}
int cnt=0,t=c[0];
for(int i=1;i<=n;i++){
t += c[i];
if(t>=k)
cnt++;
}
cout<<cnt<<endl;
return 0;
} package main
import "fmt"
func main() {
var n, k, a int
ans, count := 0, 0
fmt.Scan(&n)
arr := make([]int, n+1)
fmt.Scan(&k)
for i := 0; i < n; i++ {
fmt.Scan(&a)
arr[max(0, i-a)]++
arr[min(n, i+a+1)]--
}
for i := 0; i < n; i++ {
count += arr[i]
if count > k {
ans++
}
}
fmt.Println(ans)
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
} import java.io.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException{
Scanner in = new Scanner(System.in);
int n= in.nextInt();
int k = in.nextInt();
int []temp=new int[n+2];
int ans=0;
for(int i=1;i<=n;i++){
int r=in.nextInt();
temp[Math.min(n+1,i+r+1)]-=1;
temp[Math.max(0,i-r)]+=1;
}
int res=0;
ans=temp[0];
for(int i=1;i<=n;i++){
ans+=temp[i];
if(ans>=k)res++;
}
System.out.println(res);
}
}
import java.util.*;
public class Main
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
int n ,k;
n = sc.nextInt();
k = sc.nextInt();
// 构造差分数组
int[] router = new int[n + 5];
int ans = 0;
for(int i = 1; i <= n; i++)
{
int sig = sc.nextInt();
for(int j = sig; j >= 0; j--)
{
if(i - j >=1)
{
router[i-j] += 1;
break;
}
}
for(int j = sig; j >=0; j--)
{
if(i + j + 1 <= n + 2)
{
router[i+j+1] -= 1;
break;
}
}
}
int init = 0;
for(int i = 1 ; i <= n; i++)
{
init += router[i];
if(init >= k)
ans += 1;
//System.out.println(init);
}
System.out.println(ans);
}
} //差分
#include<iostream>
using namespace std;
const int N = 1e5 + 5;
int a[N];
int diff[N];
int n, k;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
//i - j <= a[i]
for (int i = 1; i <= n; i++) {
diff[max(1, i - a[i])]++;
diff[min(n + 1, i + a[i] + 1)]--;
}
int ans = 0;
for (int i = 1; i <= n; ++i) {
diff[i] += diff[i - 1];
if (diff[i] >= k) {
ans++;
}
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int k=scanner.nextInt();
int[] a=new int[n+1];
int[] countl=new int[n+1];
int[] countr=new int[n+1];
for(int i=1;i<=n;i++){
a[i]=scanner.nextInt();
}
for(int i=2;i<=n;i++){
if(Math.abs(i-1)<=a[i]) {//1号收到来自右边的信号
countr[1]+=1;
}
}
for(int i=2;i<=n;i++){
countr[i]=countr[i-1];//i接受右边到的信号数量应该等于i-1接收到的数量
if(a[i]>=1) countr[i]-=1;//如果i给i-1提供了信号,那么i右边信号量-1
}
// for(int i=1;i<=n;i++) System.out.print(countl[i]);
// System.out.println();
for(int i=n-1;i>=0;i--){
if(Math.abs(i-n)<=a[i]) {//n号收到来自左边的信号
countl[n]+=1;
}
}
for(int i=n-1;i>=0;i--){
countl[i]=countl[i+1];
if(a[i]>=1) countl[i]-=1;
}
// for(int i=1;i<=n;i++) System.out.print(countr[i]);
// System.out.println();
int ans=0;
for(int i=1;i<=n;i++)
if((countl[i]+countr[i]+1)>=k) ans++;
System.out.println(ans);
}
}
这样只通过了1/3,为什么呢?
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n, k;
cin >> n >> k;
vector<int>distances(n);
for(int i = 0; i < n; i++)
{
cin >> distances[i];
}
vector<int>chafen_counts(n, 0);
for(int i = 0; i < n; i++)
{
if(i - distances[i] > 0)
{
chafen_counts[i - distances[i]] += 1;
}
else
{
chafen_counts[0] += 1;
}
if(i + distances[i] + 1 <= n-1)
{
chafen_counts[i + distances[i] + 1] -= 1;
}
}
for(int i = 0; i < n; i++)
{
if(i > 0)
{
chafen_counts[i] += chafen_counts[i - 1];
}
}
int number = 0;
for(int i = 0; i < n; i++)
{
if(chafen_counts[i] >= k)
{
number++;
}
}
cout << number;
return 0;
} 首先得明白差分数组的概念。
差分数组:对于数组[a1,a2,a3,a4...],其差分数组[a1,a2-a1,a3-a2,a4-a3...]。第i项的值等于查分数组前i项的和。
这个概念有什么用呢?加入我们需要在[i,j)范围内都进行+1操作,对于原数组,可以遍历第i到j项都进行+1,但这样时间复杂度有点大。
如果用了差分数组,就可以在第i项+1,第j+1项-1就行了。只需操作两个地方。
对于这题,某一个路由器ax,其辐射的范围从i到j,我们如果遍历每个x,再从对应的i到j都+1操作,时间复杂度太大。那么就可以用差分数组。
用一个数组dp[]表示第i个路由器能接受到多少个信号,都是从0开始,遍历路由器数组arr[],计算出每一个路由器辐射的范围,start到end,然后对差分数组进行dp[start]++,dp[end+1]--操作,即表示对结果数组从start到end进行+1操作.
首先得明白差分数组的概念。
差分数组:对于数组[a1,a2,a3,a4...],其查分数组[a1,a2-a1,a3-a2,a4-a3...]。第i项的值等于查分数组前i项的和。
这个概念有什么用呢?加入我们需要在[i,j)范围内都进行+1操作,对于原数组,可以遍历第i到j项都进行+1,但这样时间复杂度有点大。
如果用了差分数组,就可以在第i项+1,第j+1项-1就行了。只需操作两个地方。
对于这题,某一个路由器ax,其辐射的范围从i到j,我们如果遍历每个x,再从对应的i到j都+1操作,时间复杂度太大。那么就可以用差分数组。
用一个数组dp[]表示第i个路由器能接受到多少个信号,都是从0开始,遍历路由器数组arr[],计算出每一个路由器辐射的范围,start到end,然后对差分数组进行dp[start]++,dp[end+1]--操作,即表示对结果数组从start到end进行+1操作.
最后,累加遍历dp数组,就能得到每一个路由器能接收的到信号数.
// 对于路由器i,它能收到信号的路由器可以分为左侧的、自己、右侧的:counter[i] = 被左侧信号覆盖 + 1 + 被右侧信号覆盖
// 被左侧信号覆盖,可以用最小优先队列实现;同理,被右侧信号覆盖,可以用最大优先队列实现。
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int solution(vector<int> &A, int k) {
if (A.size()<k || A.empty()) return 0;
priority_queue<int, vector<int>, greater<int>> q_l;
priority_queue<int> q_r;
vector<int> counter(A.size());
for (int i=0; i<A.size(); ++i) {
while (!q_l.empty() && q_l.top()<i) q_l.pop();
counter[i] += q_l.size();
q_l.push(i+A[i]);
}
for (int i=A.size()-1; i>=0; --i) {
while (!q_r.empty() && q_r.top()>i) q_r.pop();
counter[i] += q_r.size();
q_r.push(i-A[i]);
}
int res=0;
for (int i=0; i<A.size(); ++i) {
if (counter[i]>=k-1) ++res;
}
return res;
}
int main(int argc, char **argv) {
ios::sync_with_stdio(false);
int n, k;
if (cin >> n >> k) {
vector<int> A(n);
for (int i=0; i<n; ++i) cin >> A[i];
cout << solution(A, k) << endl;
}
return 0;
}