題目描述:
Elsie 正在試圖向 Bessie 描述她最喜歡的 USACO 競賽,但 Bessie 很難理解為什麼 Elsie 這麼喜歡它。Elsie 説「現在是哞哞時間!誰想哞哞?請,我只想參加 USACO」。
Bessie 仍然不理解,於是她將 Elsie 的描述轉文字得到了一個長為 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_02)的字符串,包含小寫字母字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_03。Elsie 認為一個包含三個字符的字符串 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_04 是一個哞叫,如果 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_05P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_06
一個三元組 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_07 是合法的,如果 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_08 且字符串 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_09

  • FJ 將字符串 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_10 在索引 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_11
  • 該三元組的值是 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_12

換句話説,該三元組的值等於 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_13
Bessie 向你進行 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_14P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_15)個查詢。在每個查詢中,她給你兩個整數 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_16P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_17P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_18P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_19),並詢問滿足 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_20P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_21 的所有合法三元組 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_07 的最大值。如果不存在合法的三元組,輸出 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_23
注意這個問題涉及到的整數可能需要使用 64 位整數類型(例如,C/C++ 中的 long long)。

輸入格式:
輸入的第一行包含兩個整數 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_14
以下一行包含 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_26
以下 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_14 行每行包含兩個整數 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_16P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_17,表示每個查詢。
輸出格式:
對於每一個查詢輸出一行,包含對於該查詢的答案。


奶牛時間(三) It’s Mooin’ Time III B


題目大意

一個包含三個字符的字符串 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_30,如果 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_31P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_32,則字符串 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_33

一個三元組 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_34,如果 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_35 且字符串 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_36 組成一個哞叫,則這個三元組是合法的,該三元組的值等於 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_37

輸入一個長為 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_38P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_39)的字符串,包含小寫字母字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_40

接下來會有 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_41P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_42)個查詢。在每個查詢中,給出兩個整數 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_43P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_44P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_45P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_46),並詢問滿足 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_47P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_48 的所有合法三元組 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_34 的最大值。如果不存在合法的三元組,輸出 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_50


題目分析

這道題我們採用貪心策略和二分優化,在區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_51 中,我們枚舉這個區間中所出現過的字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_52,找兩個位置 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_53,使 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_54,則 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_55 就充當 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_56,對於 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_56,我們可以確定 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_58 應為區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_51 中最後一個字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_52,而 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_61 應從區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_51 第一個字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_52 枚舉到最後一個字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_52 之前,在此過程中,P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_65 一直不變,即為區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_51 中第一個不為 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_52


解法步驟

  1. 將給出的字符串中出現的字符分類,統計每種字符出現的位置,在每次詢問中,執行以下操作:
  2. 給出區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_68,遍歷字符串中出現的每種字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69(即使在區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_68
  3. 找到區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_68 中第一個與 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69 不相同的字符的位置,記錄為 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_73(枚舉即可);
  4. 找到區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_68 中最後一個 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69 字符,記錄其位置為 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_76,找到區間 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_68 中第一個 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69 字符,記錄其指針為 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_79,指針 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_79 向後枚舉(字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69
  5. P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_79 所指的位置即為 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_83,本次得到的三元組的值為 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_84,更新結果 P3118 [USACO15JAN]電影移動Moovie Mooving_#USACO_85

代碼指導

  1. 可以使用 vector 容器儲存每種字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69
  2. 可以使用語句 auto it=upper_bound(G[id].begin(),G[id].end(),l); 來找到區間中字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69
  3. 可以使用語句 auto itt=upper_bound(G[id].begin(),G[id].end(),r);itt--; 來找到區間中字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_69
  4. P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_89 位置枚舉過程中,可以添加語句 if ((long long)d*_d<=num) break;,表示如果當前的 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_90 小於或等於已有的 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_91 就可以不再繼續枚舉,因為 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_89

AC Code

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
char s[N];
vector<int>G[N],K;
map<char,int>mp;
int main()
{
	int n,q,id=0;
	scanf("%d%d",&n,&q);
	scanf("%s",s+1);
	for (int i=1; i<=n; i++)
	{
		if (!mp[s[i]]) mp[s[i]]=++id;
		G[mp[s[i]]].push_back(i);
	}
	for (int i=1; i<=n; i++) K.push_back(mp[s[i]]);
	sort(K.begin(),K.end());
	K.erase(unique(K.begin(),K.end()),K.end());
	while (q--)
	{
		int l,r;
		long long ans=-1;
		scanf("%d%d",&l,&r);
		for (int id : K)
		{
			long long num=-1;
			auto it=upper_bound(G[id].begin(),G[id].end(),l);
			auto itt=upper_bound(G[id].begin(),G[id].end(),r);
			itt--;
			int e=l;
			while (mp[s[e]]==id) e++;
			while (it!=itt&&it!=G[id].end()&&*it<=e) it++;
			while (it!=itt&&it!=G[id].end())
			{
				int d=*it-e;
				int _d=*itt-*it;
				if ((long long)d*_d<=num) break;
				num=max(num,(long long)d*_d);
				it++;
			}
			ans=max(ans,num);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

時間複雜度

P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_93 次詢問,枚舉字符 P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_52P3118 [USACO15JAN]電影移動Moovie Mooving_#算法_95 種,P3118 [USACO15JAN]電影移動Moovie Mooving_#枚舉_61 枚舉的次數為 P3118 [USACO15JAN]電影移動Moovie Mooving_#c++_97,時間複雜度為 P3118 [USACO15JAN]電影移動Moovie Mooving_#二分_98

作者:ZZA000HAH