注意力调度问题
题意
给定长度为 的序列,每个位置
有一个
维特征向量
和一个容量
。先对每个向量做 RMSNorm 归一化,然后对任意
(
)计算贡献
。每个位置
最多选
条来自前序位置的入边,要求选边使得总贡献
最大,输出
。
思路
拆开来看,每个位置 的选边是独立的——位置
选谁做入边,不影响位置
(
)的可选集合。所以不存在全局竞争,每个位置各自贪心就行。
具体做法:
- 对每个向量做 RMSNorm:
,归一化向量
。
- 对每个位置
,枚举所有
,算出贡献
。
- 把这些贡献从大到小排序,取前
个累加到
。
- 最后输出
。
为什么每个位置独立贪心就是最优?
关键在于:入边选择没有"排他性"。位置 被位置
选为入边,不妨碍位置
(
)也选
做入边。容量限制
只约束"
自己最多收几条边",不约束"
最多被引用几次"。所以每个
的决策互不干扰,各自选最大的
个贡献即可。
拿样例验证:,归一化后
、
、
、
。
各对贡献(除以 ):
容量 :
:
,不选。
:
,选最大的
。
:
,选最大的
。
:
,选最大的两个
和
(或
,一样大)。
,输出
。
复杂度
- 时间:
,对每个
枚举
算点积
,排序
- 空间:
代码
import math
def solve():
n, d = map(int, input().split())
vecs = []
for _ in range(n):
x = list(map(float, input().split()))
vecs.append(x)
caps = list(map(int, input().split()))
normed = []
for x in vecs:
rms = math.sqrt(sum(v * v for v in x) / d)
normed.append([v / rms for v in x])
S = 0.0
for j in range(n):
if caps[j] == 0:
continue
scores = []
for i in range(j):
dot = sum(normed[i][k] * normed[j][k] for k in range(d))
scores.append(dot * dot / d)
scores.sort(reverse=True)
take = min(caps[j], len(scores))
S += sum(scores[:take])
print(round(100 * S))
solve()
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, d;
scanf("%d%d", &n, &d);
vector<vector<double>> v(n, vector<double>(d));
for(int i = 0; i < n; i++){
double ss = 0;
for(int j = 0; j < d; j++){
scanf("%lf", &v[i][j]);
ss += v[i][j] * v[i][j];
}
double rms = sqrt(ss / d);
for(int j = 0; j < d; j++) v[i][j] /= rms;
}
vector<int> c(n);
for(int i = 0; i < n; i++) scanf("%d", &c[i]);
double S = 0;
for(int j = 1; j < n; j++){
if(c[j] == 0) continue;
vector<double> scores;
for(int i = 0; i < j; i++){
double dot = 0;
for(int k = 0; k < d; k++) dot += v[i][k] * v[j][k];
scores.push_back(dot * dot / d);
}
sort(scores.rbegin(), scores.rend());
int take = min(c[j], (int)scores.size());
for(int t = 0; t < take; t++) S += scores[t];
}
printf("%lld\n", llround(100.0 * S));
return 0;
}

京公网安备 11010502036488号