diff --git a/atcoder-problems-frontend/src/pages/ListPage/ListTable.tsx b/atcoder-problems-frontend/src/pages/ListPage/ListTable.tsx
index 35dd95b49..031fa5bce 100644
--- a/atcoder-problems-frontend/src/pages/ListPage/ListTable.tsx
+++ b/atcoder-problems-frontend/src/pages/ListPage/ListTable.tsx
@@ -42,6 +42,8 @@ import {
   useProblemModelMap,
   useRatingInfo,
 } from "../../api/APIClient";
+import { classifyContest } from "../../utils/ContestClassifier";
+import { getLikeContestCategory } from "../../utils/LikeContestUtils";
 
 export const INF_POINT = 1e18;
 
@@ -113,6 +115,8 @@ interface Props {
     | "Only Rated"
     | "Only Unrated"
     | "Only Unrated without Difficulty";
+  contestCategoryFilterState: string;
+  mergeLikeContest: boolean;
   fromDifficulty: number;
   toDifficulty: number;
   filteredSubmissions: Submission[];
@@ -629,6 +633,18 @@ export const ListTable: React.FC<Props> = (props) => {
               return !isRated && !hasDifficulty;
           }
         })
+        .filter((row): boolean => {
+          if (props.contestCategoryFilterState === "All") return true;
+          if (!row.contest) return false;
+          const contest = contestMap?.get(row.contest.id);
+          const contestCategory = classifyContest(contest);
+          return (
+            props.contestCategoryFilterState === contestCategory ||
+            (props.mergeLikeContest &&
+              getLikeContestCategory(props.contestCategoryFilterState) ===
+                contestCategory)
+          );
+        })
         .filter((row) => {
           const difficulty = isProblemModelWithDifficultyModel(row.problemModel)
             ? row.problemModel.difficulty
diff --git a/atcoder-problems-frontend/src/pages/ListPage/ProblemList.tsx b/atcoder-problems-frontend/src/pages/ListPage/ProblemList.tsx
index 6d16e28e0..8c9e3b407 100644
--- a/atcoder-problems-frontend/src/pages/ListPage/ProblemList.tsx
+++ b/atcoder-problems-frontend/src/pages/ListPage/ProblemList.tsx
@@ -1,5 +1,5 @@
 import { Range } from "immutable";
-import React from "react";
+import { React, useMemo, useState } from "react";
 import { Link, useHistory, useLocation } from "react-router-dom";
 import {
   Button,
@@ -24,6 +24,8 @@ import {
 } from "../../utils/ProblemSelection";
 import { useLoginState } from "../../api/InternalAPIClient";
 import { useMergedProblemMap } from "../../api/APIClient";
+import { ContestCategories } from "../../utils/ContestClassifier";
+import { isLikeContestCategory } from "../../utils/LikeContestUtils";
 import { INF_POINT, ListTable, StatusFilter, statusFilters } from "./ListTable";
 
 export const FilterParams = {
@@ -31,8 +33,10 @@ export const FilterParams = {
   ToPoint: "toPo",
   Status: "status",
   Rated: "rated",
+  Category: "category",
   FromDifficulty: "fromDiff",
   ToDifficulty: "toDiff",
+  mergeLikeContest: "mergeLikeContest",
   Language: "Lang",
 } as const;
 
@@ -55,12 +59,14 @@ const RATED_FILTERS = [
 ] as const;
 type RatedFilter = typeof RATED_FILTERS[number];
 
+const categoryFilters = ["All", ...ContestCategories] as const;
+type CategoryFilter = typeof categoryFilters[number];
 interface Props {
   userId: string;
   submissions: Submission[];
 }
 
-export const ProblemList: React.FC<Props> = (props) => {
+export const ProblemList: React.FC<Props> = (props: Props) => {
   const location = useLocation();
   const history = useHistory();
 
@@ -91,6 +97,10 @@ export const ProblemList: React.FC<Props> = (props) => {
   const ratedFilterState: RatedFilter =
     RATED_FILTERS.find((x) => x === searchParams.get(FilterParams.Rated)) ??
     "All";
+  const contestCategoryFilterState: CategoryFilter =
+    categoryFilters.find(
+      (x) => x === searchParams.get(FilterParams.Category)
+    ) ?? "All";
 
   const languages = ["All"].concat(
     Array.from(
@@ -112,6 +122,7 @@ export const ProblemList: React.FC<Props> = (props) => {
     searchParams.get(FilterParams.ToDifficulty) || INF_POINT.toString(),
     10
   );
+  const [mergeLikeContest, setMergeLikeContest] = useState(true);
   const mergedProblemMap =
     useMergedProblemMap().data ?? new Map<ProblemId, MergedProblem>();
   const points = Array.from(
@@ -130,6 +141,14 @@ export const ProblemList: React.FC<Props> = (props) => {
 
   const loginState = useLoginState().data;
   const isLoggedIn = UserState.isLoggedIn(loginState);
+  const filteredCategoryFilters = useMemo(() => {
+    return categoryFilters.filter(
+      (category) =>
+        category === "All" ||
+        !mergeLikeContest ||
+        !isLikeContestCategory(category)
+    );
+  }, [mergeLikeContest]);
   return (
     <>
       <Row className="my-2 border-bottom">
@@ -210,6 +229,33 @@ export const ProblemList: React.FC<Props> = (props) => {
             </DropdownMenu>
           </UncontrolledDropdown>
         </ButtonGroup>
+        <ButtonGroup className="mr-4">
+          <UncontrolledDropdown>
+            <DropdownToggle caret>
+              {contestCategoryFilterState === "All"
+                ? "Category"
+                : contestCategoryFilterState}
+            </DropdownToggle>
+            <DropdownMenu>
+              {filteredCategoryFilters.map((value) => (
+                <DropdownItem
+                  key={value}
+                  tag={Link}
+                  to={generatePathWithParams(location, {
+                    [FilterParams.Category]: value,
+                  })}
+                >
+                  {value}
+                </DropdownItem>
+              ))}
+            </DropdownMenu>
+          </UncontrolledDropdown>
+          <Button onClick={(): void => setMergeLikeContest(!mergeLikeContest)}>
+            {mergeLikeContest
+              ? 'Merging "-Like" Contest'
+              : 'Unmerging "-Like" Contest'}
+          </Button>
+        </ButtonGroup>
         <ButtonGroup className="mr-4">
           <UncontrolledDropdown>
             <DropdownToggle caret>
@@ -325,6 +371,8 @@ export const ProblemList: React.FC<Props> = (props) => {
           toPoint={toPoint}
           statusFilterState={statusFilterState}
           ratedFilterState={ratedFilterState}
+          contestCategoryFilterState={contestCategoryFilterState}
+          mergeLikeContest={mergeLikeContest}
           fromDifficulty={fromDifficulty}
           toDifficulty={toDifficulty}
           filteredSubmissions={props.submissions}
diff --git a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendController.tsx b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendController.tsx
index aa8410a03..9f4639fa3 100644
--- a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendController.tsx
+++ b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendController.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import { React, useMemo } from "react";
 import {
   Button,
   ButtonGroup,
@@ -9,7 +9,7 @@ import {
   UncontrolledDropdown,
 } from "reactstrap";
 import { formatExcludeOption } from "../../../utils/LastSolvedTime";
-
+import { isLikeContestCategory } from "../../../utils/LikeContestUtils";
 const RECOMMEND_NUM_OPTIONS = [
   {
     text: "10",
@@ -47,6 +47,18 @@ const ExcludeOptions = [
 ] as const;
 export type ExcludeOption = typeof ExcludeOptions[number];
 
+const CategoryOptions = [
+  "All",
+  "ABC",
+  "ARC",
+  "AGC",
+  "ABC-Like",
+  "ARC-Like",
+  "AGC-Like",
+  "Other Sponsored",
+] as const;
+export type CategoryOption = typeof CategoryOptions[number];
+
 interface Props {
   recommendOption: RecommendOption;
   onChangeRecommendOption: (option: RecommendOption) => void;
@@ -54,73 +66,123 @@ interface Props {
   excludeOption: ExcludeOption;
   onChangeExcludeOption: (option: ExcludeOption) => void;
 
+  categoryOption: CategoryOption;
+  onChangeCategoryOption: (option: CategoryOption) => void;
+
   showExperimental: boolean;
   onChangeExperimentalVisibility: (showExperimental: boolean) => void;
+  mergeLikeContest: boolean;
+  onChangeMergeLikeContest: (mergeLikeContest: boolean) => void;
 
   showCount: number;
   onChangeShowCount: (count: number) => void;
 }
 
-export const RecommendController = (props: Props) => (
-  <>
-    <div>
-      <ButtonGroup className="mr-3">
-        {RecommendOptions.map((type) => (
-          <Button
-            key={type}
-            active={props.recommendOption === type}
-            onClick={() => props.onChangeRecommendOption(type)}
-          >
-            {type}
-          </Button>
-        ))}
-      </ButtonGroup>
-      <ButtonGroup className="mr-3">
-        <UncontrolledDropdown>
-          <DropdownToggle caret>
-            {formatExcludeOption(props.excludeOption)}
-          </DropdownToggle>
-          <DropdownMenu>
-            {ExcludeOptions.map((option) => (
-              <DropdownItem
-                key={option}
-                onClick={(): void => props.onChangeExcludeOption(option)}
-              >
-                {formatExcludeOption(option)}
-              </DropdownItem>
-            ))}
-          </DropdownMenu>
-        </UncontrolledDropdown>
-      </ButtonGroup>
-      <CustomInput
-        type="switch"
-        id="switchRecommendExperimental"
-        inline
-        label={
-          <span role="img" aria-label="experimental">
-            🧪
-          </span>
-        }
-        checked={props.showExperimental}
-        onChange={() =>
-          props.onChangeExperimentalVisibility(!props.showExperimental)
-        }
-      />
-    </div>
-    <UncontrolledDropdown direction="left">
-      <DropdownToggle caret>
-        {props.showCount === Number.POSITIVE_INFINITY ? "All" : props.showCount}
-      </DropdownToggle>
-      <DropdownMenu>
-        {RECOMMEND_NUM_OPTIONS.map(({ text, value }) => (
-          <DropdownItem
-            key={value}
-            onClick={(): void => props.onChangeShowCount(value)}
-          >
-            {text}
-          </DropdownItem>
-        ))}
-      </DropdownMenu>
-    </UncontrolledDropdown>
-  </>
-);
+export const RecommendController = (props: Props) => {
+  const filteredCategories = useMemo(() => {
+    return CategoryOptions.filter(
+      (category) =>
+        category === "All" ||
+        !props.mergeLikeContest ||
+        !isLikeContestCategory(category)
+    );
+  }, [props.mergeLikeContest]);
+  return (
+    <>
+      <div>
+        <ButtonGroup className="mr-3">
+          {RecommendOptions.map((type) => (
+            <Button
+              key={type}
+              active={props.recommendOption === type}
+              onClick={() => props.onChangeRecommendOption(type)}
+            >
+              {type}
+            </Button>
+          ))}
+        </ButtonGroup>
+        <ButtonGroup className="mr-3">
+          <UncontrolledDropdown>
+            <DropdownToggle caret>
+              {formatExcludeOption(props.excludeOption)}
+            </DropdownToggle>
+            <DropdownMenu>
+              {ExcludeOptions.map((option) => (
+                <DropdownItem
+                  key={option}
+                  onClick={(): void => props.onChangeExcludeOption(option)}
+                >
+                  {formatExcludeOption(option)}
+                </DropdownItem>
+              ))}
+            </DropdownMenu>
+          </UncontrolledDropdown>
+        </ButtonGroup>
+        <ButtonGroup className="mr-3">
+          <UncontrolledDropdown>
+            <DropdownToggle caret>
+              {props.categoryOption === "All"
+                ? "Contest Category"
+                : props.categoryOption}
+            </DropdownToggle>
+            <DropdownMenu>
+              {filteredCategories.map((option) => (
+                <DropdownItem
+                  key={option}
+                  onClick={(): void => props.onChangeCategoryOption(option)}
+                >
+                  {option}
+                </DropdownItem>
+              ))}
+            </DropdownMenu>
+          </UncontrolledDropdown>
+        </ButtonGroup>
+        <CustomInput
+          type="switch"
+          id="switchRecommendExperimental"
+          inline
+          label={
+            <span role="img" aria-label="experimental">
+              🧪
+            </span>
+          }
+          checked={props.showExperimental}
+          onChange={() =>
+            props.onChangeExperimentalVisibility(!props.showExperimental)
+          }
+        />
+        <CustomInput
+          type="switch"
+          id="switchMergeLikeContest"
+          inline
+          label={
+            <span role="img" aria-label="experimental">
+              Merge &quot;-Like&quot; Contests
+            </span>
+          }
+          checked={props.mergeLikeContest}
+          onChange={() =>
+            props.onChangeMergeLikeContest(!props.mergeLikeContest)
+          }
+        />
+      </div>
+      <UncontrolledDropdown direction="left">
+        <DropdownToggle caret>
+          {props.showCount === Number.POSITIVE_INFINITY
+            ? "All"
+            : props.showCount}
+        </DropdownToggle>
+        <DropdownMenu>
+          {RECOMMEND_NUM_OPTIONS.map(({ text, value }) => (
+            <DropdownItem
+              key={value}
+              onClick={(): void => props.onChangeShowCount(value)}
+            >
+              {text}
+            </DropdownItem>
+          ))}
+        </DropdownMenu>
+      </UncontrolledDropdown>
+    </>
+  );
+};
diff --git a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendProblems.ts b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendProblems.ts
index 7020bc947..320bebd2d 100644
--- a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendProblems.ts
+++ b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/RecommendProblems.ts
@@ -3,7 +3,7 @@ import ProblemModel, {
   isProblemModelWithDifficultyModel,
   isProblemModelWithTimeModel,
 } from "../../../interfaces/ProblemModel";
-import { ProblemId } from "../../../interfaces/Status";
+import { ContestId, ProblemId } from "../../../interfaces/Status";
 import {
   predictSolveProbability,
   predictSolveTime,
@@ -58,6 +58,7 @@ const getRecommendProbabilityRange = (
 export const recommendProblems = (
   problems: Problem[],
   isIncluded: (problemId: ProblemId) => boolean,
+  isIncludedContestCategory: (contestId: ContestId) => boolean,
   getProblemModel: (problemId: ProblemId) => ProblemModel | undefined,
   recommendExperimental: boolean,
   internalRating: number | null,
@@ -68,6 +69,7 @@ export const recommendProblems = (
   const recommendRange = getRecommendProbabilityRange(recommendOption);
   return problems
     .filter((p) => isIncluded(p.id))
+    .filter((p) => isIncludedContestCategory(p.contest_id))
     .map((p) => ({
       ...p,
       difficulty: getProblemModel(p.id)?.difficulty,
diff --git a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx
index 9c556870e..7c75c4b64 100644
--- a/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx
+++ b/atcoder-problems-frontend/src/pages/UserPage/Recommendations/index.tsx
@@ -15,7 +15,7 @@ import { HelpBadgeTooltip } from "../../../components/HelpBadgeTooltip";
 import { NewTabLink } from "../../../components/NewTabLink";
 import { ProblemLink } from "../../../components/ProblemLink";
 import Problem from "../../../interfaces/Problem";
-import { ProblemId } from "../../../interfaces/Status";
+import { ContestId, ProblemId } from "../../../interfaces/Status";
 import {
   formatPredictedSolveProbability,
   formatPredictedSolveTime,
@@ -34,8 +34,14 @@ import {
   getLastSolvedTimeMap,
   getMaximumExcludeElapsedSecond,
 } from "../../../utils/LastSolvedTime";
+import { classifyContest } from "../../../utils/ContestClassifier";
+import { getLikeContestCategory } from "../../../utils/LikeContestUtils";
 import { recommendProblems } from "./RecommendProblems";
-import { RecommendController, RecommendOption } from "./RecommendController";
+import {
+  CategoryOption,
+  RecommendController,
+  RecommendOption,
+} from "./RecommendController";
 
 interface Props {
   userId: string;
@@ -54,6 +60,16 @@ export const Recommendations = (props: Props) => {
     "recoomendExcludeOption",
     "Exclude"
   );
+
+  const [mergeLikeContest, setMergeLikeContest] = useLocalStorage<boolean>(
+    "recommendMergeLikeContest",
+    true
+  );
+
+  const [categoryOption, setCategoryOption] = useLocalStorage<CategoryOption>(
+    "recommendCategoryOption",
+    "All"
+  );
   const [recommendNum, setRecommendNum] = useState(10);
 
   const [
@@ -105,6 +121,18 @@ export const Recommendations = (props: Props) => {
         : Number.MAX_SAFE_INTEGER;
       return getMaximumExcludeElapsedSecond(excludeOption) < elapsedSecond;
     },
+    (contestId: ContestId) => {
+      if (categoryOption === "All") return true;
+      const contest = contestMap?.get(contestId);
+      if (!contest) {
+        return false;
+      }
+      return (
+        classifyContest(contest) === categoryOption ||
+        (mergeLikeContest &&
+          classifyContest(contest) === getLikeContestCategory(categoryOption))
+      );
+    },
     (problemId: ProblemId) => problemModels?.get(problemId),
     recommendExperimental,
     userRatingInfo.internalRating,
@@ -120,10 +148,14 @@ export const Recommendations = (props: Props) => {
           onChangeRecommendOption={(option) => setRecommendOption(option)}
           excludeOption={excludeOption}
           onChangeExcludeOption={(option) => setExcludeOption(option)}
+          categoryOption={categoryOption}
+          onChangeCategoryOption={(option) => setCategoryOption(option)}
           showExperimental={recommendExperimental}
           onChangeExperimentalVisibility={(show) =>
             setRecommendExperimental(show)
           }
+          mergeLikeContest={mergeLikeContest}
+          onChangeMergeLikeContest={(merge) => setMergeLikeContest(merge)}
           showCount={recommendNum}
           onChangeShowCount={(value) => setRecommendNum(value)}
         />
diff --git a/atcoder-problems-frontend/src/utils/LocalStorage.tsx b/atcoder-problems-frontend/src/utils/LocalStorage.tsx
index 7cfa14de2..f78e14923 100644
--- a/atcoder-problems-frontend/src/utils/LocalStorage.tsx
+++ b/atcoder-problems-frontend/src/utils/LocalStorage.tsx
@@ -16,7 +16,9 @@ const LocalStorageKeys = [
   "showRating",
   "recommendOption",
   "recommendExperimental",
+  "recommendMergeLikeContest",
   "recoomendExcludeOption",
+  "recommendCategoryOption",
   "MergeLikeContest",
 ] as const;
 type LocalStorageKey = typeof LocalStorageKeys[number];