Either way, you have to join to the same table twice.
With joins instead of IN:
WITH cm AS (SELECT n FROM tbl1 WHERE c = 41)
SELECT t.nn
FROM   tbl2    t
JOIN   cm      c1 ON c1.n = t.n
LEFT   JOIN cm c2 ON c2.n = t.nn
WHERE  c2.n IS NULL;
The same without CTE:
SELECT t.nn
FROM   tbl2      t
JOIN   tbl1      t1 USING (n)  -- equivalent to "ON t1.n = t.n" here
LEFT   JOIN tbl1 t2 ON t2.n = t.nn
                   AND t2.c = 41  -- must go here!
WHERE  t1.c = 41
AND    t2.n IS NULL;
Requires that cm.n is UNIQUE / tbl1.n is UNIQUE for tbl1.c = 41.
See:
While cm.n is never NULL, your original works, too:
WITH cm AS (SELECT n FROM tbl1 WHERE c = 41)
SELECT t.nn
FROM   tbl2 t
WHERE  n      IN (TABLE cm)
AND    nn NOT IN (TABLE cm);
Simplified with short syntax TABLE. See:
But I'd rather use NOT EXISTS instead of NOT IN. Typically faster and does not fail surprisingly with NULL values.
WITH cm AS (SELECT n FROM tbl1 WHERE c = 41)
SELECT t.nn
FROM   tbl2 t
WHERE  EXISTS     (SELECT FROM cm WHERE n = t.n)
AND    NOT EXISTS (SELECT FROM cm WHERE n = t.nn)
EXISTS never duplicates rows (like IN). And it works as expected when NULL values are involved (like JOIN). So it's typically my first choice.
See: