According to the following page, a primary key is used for both LIKE and NOT LIKE conditions:
https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree/#functions-support

As I found, a primary key is not used for NOT LIKE 'prefix%' conditions, engine scans all granules.

**How to reproduce**
ClickHouse Playground:
https://fiddle.clickhouse.com/095384c8-7b7e-45ec-b7e7-42dc8150be89

```
CREATE TABLE data
(str String)
ENGINE=MergeTree
ORDER BY str;

INSERT INTO data (str)
SELECT 'aa' FROM numbers(100000);

INSERT INTO data (str)
SELECT 'ba' FROM numbers(100000);

INSERT INTO data (str)
SELECT 'ca' FROM numbers(100000);

SET send_logs_level='trace';

SELECT count()
FROM data
WHERE str NOT LIKE 'a%';
```

`(SelectExecutor): Selected 3/3 parts by partition key, 3 parts by primary key, 36/36 marks by primary key, 36 marks to read from 3 ranges`

**Additional context**
Primary key is used for LIKE conditions, engine skips granules:
https://fiddle.clickhouse.com/95dd14a6-2e9f-4c45-94cd-169233f2a702

Primary key is used for != conditions, engine skips granules:
https://fiddle.clickhouse.com/e208b937-20c3-4cc0-896b-bfe83b42454a

return applyFunctionForField(func, current_type, field);
    String result_name = "_" + func->getName() + "_" + toString(field.column_idx);
    const auto & columns = field.columns;
    size_t result_idx = columns->size();
    for (size_t i = 0; i < result_idx; ++i)
    {
        if ((*columns)[i].name == result_name)
            result_idx = i;
    }
    if (result_idx == columns->size())
    {
        ColumnsWithTypeAndName args{(*columns)[field.column_idx]};
        field.columns->emplace_back(ColumnWithTypeAndName {nullptr, func->getResultType(), result_name});
        (*columns)[result_idx].column = func->execute(args, (*columns)[result_idx].type, columns->front().column->size());
    }
    return {field.columns, field.row_idx, result_idx};
}
/** The key functional expression constraint may be inferred from a plain column in the expression.
  * For example, if the key contains `toStartOfHour(Timestamp)` and query contains `WHERE Timestamp >= now()`,
  * it can be assumed that if `toStartOfHour()` is monotonic on [now(), inf), the `toStartOfHour(Timestamp) >= toStartOfHour(now())`
  * condition also holds, so the index may be used to select only parts satisfying this condition.
  *
  * To check the assumption, we'd need to assert that the inverse function to this transformation is also monotonic, however the
  * inversion isn't exported (or even viable for not strictly monotonic functions such as `toStartOfHour()`).
  * Instead, we can qualify only functions that do not transform the range (for example rounding),
  * which while not strictly monotonic, are monotonic everywhere on the input range.
  */
bool KeyCondition::transformConstantWithValidFunctions(
    const String & expr_name,
    size_t & out_key_column_num,