先上代码

for (int i = 2; i < N; i++) {//筛出严格小于 N 的素数
  if (!vis[i]) pri.push_back(i), vis[i] = 1;
  for (int j = 0; j < pri.size(); j++) {
    long long v = (long long)i*pri[j]; //是否要用 ll 要看你筛素数的范围
    if (v >= N) break;
    vis[v] = 1;
    if (i%pri[j] == 0) break; //剪枝魔法
  }
}
//严格小于N的素数(除了1)被放进了pri数组里。所以你如果想要完整的有序素数表,要在一开始push 1并且把第三行j的初值改到1。

假如没有第7行,这个代码肯定是对的(尽管我们感觉效率不太高)。
那第七行是个什么意思呢。
它保证了 每个数只会被其最小的质因子筛去
我们把每个合数表示成 x = s*p 的形式。其中 p 是 x 的最小质因子。
然后我们每次筛法枚举的 i 相当于 s。
设break时的下标为k。
由于 pri[] 有序,那么显然 pri[k] 是 i 的最小质因子,并且 pri[k] > pri[1 … k - 1]。

对于 pri[1 <= j <= k - 1], i*pri[j] 中 i 的最小质因子 pri[k] 都大于 pri[j],所以i*pri[j]的最小质因子是 pri[j]。
所以 i 就是 s, pri[j] 就是 p。

对于 pri[j > k],i*pri[j] 中 i 有质因子 pri[k],并且 pri[k] < pri[j],所以 pri[j] 不可能是最小质因子。因此break,不循环了。