• LeetCode Hard 选做


    题目链接


    感受一下自己能不能切lc的hard题(退役后这么闲的怕是就我一个)。
    hard间难度差异很大,有的巨水像easy,所以可能会挑着做。
    基本都是DP/数学/计算几何,我这种主做数据结构的怎么办


    做了十几道Hard,没想到LeetCode Hard题比我想象的还要简单。。而且感觉连题意都不会描述(更不要说数据范围),放NOIP普及组都能被冲爆。
    最近许多比赛的Hard也依然很水((approx)牛客小白月赛的难题),真hard的应该很少很少。
    (它这周赛随便找个OIer/ACMer都能出)

    总之,Hard难度区间大概在 我高中学OI 半个月到八九个月左右 的水平。

    不想做了太无聊了。做算法入门题还行,但大厂算法面试就这?这也叫算法?绝了。


    4. 寻找两个正序数组的中位数

    /*
    easy题。
    log做法的话,因为目标是找合并后第k大的值,设两个数组为v1,v2,假设第k大在第一个数组的v1[p]位置,那么对第二个数组的k-p位置,应有v1[p]>=v2[k-p-1],否则v1取的元素不够,p需右移。
    p移动是单调的,所以可以二分。
    */
    #include <bits/stdc++.h>
    using namespace std;
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=1e5+5;
    
    	int A[N];
    
    	double findMedianSortedArrays(vector<int>& v1, vector<int>& v2)
    	{
    		std::vector<int> vec;
    		auto it1=v1.begin(),it2=v2.begin();
    		while(it1!=v1.end() || it2!=v2.end())
    		{
    			if(it1==v1.end()||(it2!=v2.end()&&*it1>*it2)) vec.pb(*it2++);
    			else vec.pb(*it1++);
    		}
    		for(auto v:vec) printf("%d ",v); pc('
    ');
    		int n=vec.size()-1;
    		return (vec[n/2]+vec[n/2+(n&1)])/2.0;
    	}
    };
    Solution sol;
    
    int main()
    {
    
    	return 0;
    }
    

    10. 正则表达式匹配

    /*
    入门DP。555人有点凌乱写得很乱。
    f[i][j]表示s的前i个字符是否能和p的前j个字符匹配,分情况讨论、转移即可。
    */
    #include <bits/stdc++.h>
    using namespace std;
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=55;
    
    	int f[N][N];
    
    	bool isMatch(string s, string p)
    	{
    		int n=s.length(),m=p.length();
    		s.insert(0,1,'@'), p.insert(0,"@");
    
    		f[0][0]=1;
    		for(int j=2; j<=m; j+=2)
    			if(p[j]=='*') f[0][j]=1;
    			else break;
    		for(int i=1; i<=n; ++i)
    			for(int j=1; j<=m; ++j)
    			{
    				if(p[j]=='*')
    				{
    					if(f[i][j-2]||f[i][j-1]) f[i][j]=1;
    					if(f[i-1][j] && (s[i]==p[j-1]||p[j-1]=='.')) f[i][j]=1;
    				}
    				else if(f[i-1][j-1]&&(s[i]==p[j]||p[j]=='.')) f[i][j]=1;
    				if(f[i][j] && j+2<=m && p[j+2]=='*') f[i][j+2]=1;
    			}
    //		for(int i=1; i<=n; ++i)
    //			for(int j=1; j<=m; ++j)
    //				printf("f[%d][%d]=%d
    ",i,j,f[i][j]);
    		return f[n][m];
    	}
    };
    Solution sol;
    
    int main()
    {
    	string a,b; cin>>a>>b;
    	printf("%d
    ",sol.isMatch(a,b));
    
    	return 0;
    }
    

    23. 合并K个升序链表

    /*
    最简单做法也是easy。做这种题有点使我变傻,真的去想一个个合并了(而且没怎么用过指针555)。
    用堆把链表里所有元素push进去,依次取建链表即可。用原有元素就行,不需要new。
    因为list有序,所以不需将所有元素push,每次push当前list最前面那个即可,每次取再push。这样就是O(log总链表数)而不是O(log总元素数)。
    得到链表的简单方式是,建一个head和*tail=&head,元素依次放入tail->next,然后更新tail=tail->next,最后返回head.next即可。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=1e5+5;
    
    	struct Node
    	{
    		int val;
    		ListNode *ptr;
    		bool operator <(const Node &x)const
    		{
    			return val>x.val;
    		}
    	};
    	std::priority_queue<Node> q;
    
    	ListNode* mergeKLists(vector<ListNode*>& ls)
    	{
    		for(auto v:ls) if(v) q.push(Node{v->val,v});//注意判v!=NULL!
    
    		ListNode head, *tail=&head;
    		while(!q.empty())
    		{
    			Node x=q.top(); q.pop();
    			tail = tail->next = x.ptr;
    			if(x.ptr->next) q.push(Node{x.ptr->next->val, x.ptr->next});
    		}
    		return head.next;
    	}
    };
    Solution sol;
    
    int main()
    {
    //	sol.Main();
    
    	return 0;
    }
    

    25. K 个一组翻转链表

    /*
    easy题。十来分钟过了,感觉做了一个题指针链表已经完全会了.jpg。
    就把链表每k个倒序存一遍(将next赋值为它原本的pre)。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=1e5+5;
    
    //	struct ListNode
    //	{
    //		int val;
    //		ListNode *next;
    //		ListNode(): val(0), next(nullptr) {}
    //		ListNode(int x): val(x), next(nullptr) {}
    //		ListNode(int x, ListNode *next): val(x), next(next) {}
    //	};
    
    	ListNode* reverseKGroup(ListNode* head, int k)
    	{
    		ListNode ans, *anst=&ans, *t=NULL, *tmp=NULL, *nxt=NULL;
    
    		int cnt=0;
    		while(head)
    		{
    			nxt = head->next;
    			if(!t) t=head, t->next=NULL;
    			else tmp=t, t=head, t->next=tmp;
    			
    			head = nxt;
    			if(++cnt==k)
    			{
    				while(t)
    					anst = anst->next = t, t = t->next;
    				t=NULL, cnt=0;
    			}
    		}
    		head=t, t=NULL;//剩下的部分已经反转了,再反转一遍即可。
    		while(head)
    		{
    			nxt = head->next;
    			if(!t) t=head, t->next=NULL;
    			else tmp=t, t=head, t->next=tmp;
    			
    			head = nxt;
    			if(!head)
    				while(t)
    					anst = anst->next = t, t = t->next;
    		}
    		return ans.next;
    	}
    };
    Solution sol;
    
    int main()
    {
    //	sol.Main();
    
    	return 0;
    }
    

    30. 串联所有单词的子串

    /*
    ...这可能算middle题?
    假设有n个单词,每个单词长为k,总长m=nk,那么位置p合法即s[p,p+m)能匹配n个单词。 
    Sol 1.
    因为单词互不相同,枚举每个长为m的区间,再对其中每个长为k的区间找出其对应的单词,看最后是否能对应所有n个单词。
    用unordered_map找对应单词,复杂度是$O(|s|*m)$。如果用Trie找对应单词是O(|s|*m*k)。
    最大复杂度实际是$O((|s|-m)*m)=O(frac{|s|^2}{4})$,所以很容易过。
    Sol 2.
    在做法1中,对很多长为k的区间,我们会重复为它找对应单词多次,事实上只需要一次。
    从s的0到k-1位置分别开始,依次对每个长为k的区间,找到它的对应单词,并保存已找到的单词数。
    当处理了n个长为k的区间时,看下现在已找到所有n个单词,然后将最早的那个区间的找到的单词删掉,再处理下个长为k的区间即可。
    用unordered_map找对应单词,复杂度$O(|s|*k)$。$k$只有30所以非常低。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=5005;
    
    	int cnt[N],CNT[N],ID[N<<1];
    	std::unordered_map<std::string, int> mp;
    
    	vector<int> findSubstring(string s, vector<string>& words)
    	{
    		int L=s.length(), n=words.size(), k=words[0].length(), m=n*k, t=0;
    		for(auto v:words)
    		{
    			if(!mp.count(v)) mp[v]=++t;
    			++CNT[mp[v]];
    		}
    		
    		std::vector<int> res;
    		for(int p=0; p<k; ++p)
    		{
    			cnt[0]=1e9;
    			int tot=0, delta=0;
    			for(int i=p; i+k<=L; i+=k)//i+k可等于k!
    			{
    				int id=mp[s.substr(i,k)];
    				ID[i]=id;
    				if(++cnt[id]<=CNT[id])
    					if(++tot==n) res.emplace_back(p+delta);
    				if(i+k-p-delta==m)
    				{
    					id=ID[p+delta];
    					if(--cnt[id]<CNT[id]) --tot;
    					delta+=k;
    				}
    			}
    			memset(cnt, 0, t+1<<2);
    		}
    		return res;
    	}
    };
    Solution sol;
    
    int main()
    {
    
    	return 0;
    }
    

    32. 最长有效括号

    /*
    算middle?
    最简单的想法,依次枚举字符,遇到'('就++top,遇到')',若top!=0,就--top,++cnt(当前右括号数),否则令cnt=0(右括号更多了,不合法)。
    然后考虑什么时候可用cnt更新答案:因为会有左括号更多的不合法情况,此时不能确定是否更新答案,所以只能在--top后,top==0时更新答案ans=max(ans, cnt*2)。
    但这样计算不了左括号数>右括号数的序列的贡献,所以将串反转、'('')'互换后,再做一遍取max即可。
    这样空间是O(1)的。
    
    还有个简单做法,将匹配上的左右括号缩成一个字符比如'1',然后统计最后序列最长连续'1'的个数。
    因为缩两个字符不方便,所以令匹配上的'('=' ',')'='1',最后' '不影响连续性。
    
    还有种好写的方法是,用栈push所有左括号位置,匹配到右括号就取一下 当前位置-上次未匹配位置(就是栈顶,初始为-1)。
    当左括号少于右括号时,清空栈,将栈顶初始值设为当前右括号位置。看代码吧。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=3e4+5;
    	
    //	int sk[N];
    
    	int Calc(string s,const char ch)
    	{
    		int top=0,ans=0,cnt=0;
    		for(auto c:s)
    			if(c==ch) ++top;
    			else if(top) --top, ++cnt, !top&&(ans=std::max(ans, cnt*2));
    			else cnt=0;
    		cout<<s<<'
    '<<ans<<'
    ';
    		return ans;
    	}
    	int longestValidParentheses(string s)
    	{
    		int tmp=Calc(s,'(');
    		std::reverse(s.begin(), s.end());//s=string(s.rbegin(),s.rend())
    		return std::max(tmp,Calc(s,')'));
    
    //		int top=0,ans=0,l=s.length();
    //Sol 2.
    //		for(int i=0; i<l; ++i)
    //		{
    //			if(s[i]=='(') sk[++top]=i;
    //			else if(top) s[i]='1', s[sk[top--]]=' ';
    //		}
    //		for(int i=0,now=0; i<l; ++i)
    //			if(s[i]=='('||s[i]==')') now=0;
    //			else if(s[i]=='1') ans=std::max(ans, ++now);
    //		return ans*2;
    //Sol 3.
    //		sk[top=1]=-1;
    //		for(int i=0; i<l; ++i)
    //			if(s[i]=='(') sk[++top]=i;
    //			else //')'
    //				if(!--top) sk[top=1]=i;//右括号更多 
    //				else ans=std::max(ans, i-sk[top]);
    //		return ans;
    	}
    };
    Solution sol;
    
    int main()
    {
    	string s; cin>>s;
    	printf("%d
    ",sol.longestValidParentheses(s));
    
    	return 0;
    }
    

    37. 解数独

    /*
    。。DFS入门题,算easy题吧。
    搞不懂为什么要bitset,用结构体存9个数的bool,枚举的时候同时看看行、列、所属块的该数bool值就行了,常数是27;用bitset或一遍得到可填数后也仍要枚举9次,且也要常数9^2/w,bitset有啥用啊。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	#define ID(x,y) ((x-1)/3*3+(y+2)/3)
    	typedef long long LL;
    	const static int N=90;
    
    	struct Node
    	{
    		int x,y;
    	}pos[N];
    	struct Status
    	{
    		bool A[9];
    	}row[10],col[10],block[10];
    
    	inline void Fill(int x,int y,int num)
    	{
    		row[x].A[num]=1, col[y].A[num]=1, block[ID(x,y)].A[num]=1;
    	}
    	inline void Unfill(int x,int y,int num)
    	{
    		row[x].A[num]=0, col[y].A[num]=0, block[ID(x,y)].A[num]=0;
    	}
    	bool DFS(int n,vector<vector<char>>& board)
    	{
    		if(!n) return 1;
    		int x=pos[n].x, y=pos[n].y; --n;
    		Status &r=row[x], &c=col[y], &b=block[ID(x,y)];
    		for(int i=8; ~i; --i)
    			if(!r.A[i] && !c.A[i] && !b.A[i])
    			{
    				Fill(x,y,i);
    				if(DFS(n,board)) return board[x-1][y-1]=i+49, 1;
    				Unfill(x,y,i);
    			}
    		return 0;
    	}
    	void solveSudoku(vector<vector<char>>& board)
    	{
    		int n=0;
    		for(int i=1; i<=9; ++i)
    		{
    			int j=1;
    			for(auto c:board[i-1])
    			{
    				if(c=='.') pos[++n]={i,j};
    				else Fill(i,j,c-'1');
    				++j;
    			}
    		}
    		DFS(n,board);
    	}
    };
    Solution sol;
    
    int main()
    {
    //	sol.Main();
    
    	return 0;
    }
    

    41. 缺失的第一个正数

    /*
    限制时间O(n)、常数级复杂度有点难,有点想不到(事实上就没见过这种O(n)读入还不让开O(n)空间的),算hard吧?(但感觉完全是个trick)
    设数组长为n,则只需一个大小为n的数组表示[1,n]中每个数是否出现过。
    因为不能开这个数组,所以考虑将给的输入数组改为那个数组,来标记[1,n]中哪些数出现过。
    有两种方法:
    1. 直接修改原数组会丢失原有的值,但我们只关心[1,n]这些值,其它无关值(不在[1,n]内)都可设成任意一个数(如n+1)。
    注意这样就可将所有数化为正数,然后在每个数前加负号,是不会丢失原有值的。所以我们用正负号做bool值:xin [1,n]出现过,就令vec[x-1]变为负(vec为给定数组)(注意不是乘-1,因为x可出现多次)。
    这个 为不影响原数组值 且不开新数组,将 正负号 作为 bool值 的思路真是没见过。
    2. 若vec[x-1]in [1,n] 且 vec[x-1]!=x,则令vec[x-1]与vec[vec[x-1]-1]交换,直到vec[x-1]
    otin [1,n] 或 vec[x-1]==x。
    可以发现最终,若xin [1,n] 且 x出现过,则一定有vec[x-1]=x。且一个位置最多被交换一次,所以均摊复杂度也是O(n)。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=1e5+5;
    
    	int firstMissingPositive(vector<int>& nums)
    	{
    		#define V 2000000000
    		int n=nums.size();
    		for(auto &v:nums)
    			if(v>n || v<=0) v=V;
    		for(auto v:nums)
    			if(std::abs(v)<=n) nums[std::abs(v)-1]=-std::abs(nums[std::abs(v)-1]); // 注意v和nums[v-1]均取abs!
    		int i=0;
    		for(auto v:nums)
    			if(++i, v>0) return i;
    		return n+1;
    	}
    };
    Solution sol;
    
    int main()
    {
    	vector<int> v; int x;
    	while(~scanf("%d",&x)) v.pb(x);
    	printf("%d
    ",sol.firstMissingPositive(v));
    
    	return 0;
    }
    

    42. 接雨水

    /*
    middle题吧,虽然也easy。
    就拿个栈存高度、位置,每次pop掉前面高度小于等于自己的,然后用他们间的距离*前面那个位置的高度差算贡献。
    发现算不了2 0 1这种左边更高的情况,将序列反转再求一遍即可(注意此时不能pop前面高度等于自己的,会重复)。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=3e4+5;
    
    	struct Node
    	{
    		int p,h;
    	}sk[N];
    
    	int trap(vector<int>& ht)
    	{
    		int n=ht.size(),ans=0,top=0,i=0;
    		sk[0]={0,(int)1e9};
    		for(auto h:ht)
    		{
    			++i;
    			for(int las=0; h>=sk[top].h; --top)
    				ans+=(sk[top].h-las)*(i-sk[top].p-1), las=sk[top].h;
    			sk[++top]={i,h};
    		}
    		
    		std::reverse(ht.begin(),ht.end());
    		sk[0]={0,(int)1e9};
    		for(auto h:ht)
    		{
    			++i;
    			for(int las=0; h>sk[top].h; --top)
    				ans+=(sk[top].h-las)*(i-sk[top].p-1), las=sk[top].h;
    			sk[++top]={i,h};
    		}
    
    		return ans;
    	}
    };
    Solution sol;
    
    int main()
    {
    	vector<int> v; int x;
    	while(~scanf("%d",&x)) v.pb(x);
    	sol.trap(v);
    
    	return 0;
    }
    

    
    

    381. O(1) 时间插入、删除和获取随机元素 - 允许重复

    /*
    这种没见过诶。。
    因为要随机获取元素,所以基本只能是将所有数存在一个vector中。插入可直接在vector末尾插入。
    直接在vector里删除是O(n)的。注意vector中数是无序的,删除一个数可以将它交换到vector尾部,然后pop_back,O(1)删除。
    这样还需要对每个数,维护它出现的下标位置,且要能O(1)动态查找、插入、删除值,只能用unordered_set(同样也是Hash实现,也有unordered_multiset)。
    
    因为vector也可以存迭代器,所以可不用下标,将unordered_map<int, unordered_set<int>>换成unordered_multimap<int, int>,vector<int>换成vector<unordered_multimap<int, int>::iterator>。
    具体细节相同。这样减少了一次哈希,常数小很多。
    
    这题竟然是通过足够多次getRandom()判答案,hhhnb,怪不得测这么慢。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class RandomizedCollection
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	typedef long long LL;
    	const static int N=1e5+5;
    
    	std::vector<int> all;
    	std::unordered_map<int, std::unordered_set<int>> mp;
    //	std::unordered_multimap<int, int> mp;
    //	vector<std::unordered_multimap<int, int>::iterator> all;
    
    	RandomizedCollection() {}
    	bool insert(int val)
    	{
    		bool ret=mp[val].empty();
    		mp[val].insert(all.size()), all.pb(val);
    		return ret;
    	}
    	bool remove(int val)
    	{
    		if(mp[val].empty()) return 0;
    
    		auto it=mp[val].begin();//unordered_set没有rbegin 
    		int pos=*it; mp[val].erase(it);
    		
    		int v2=*all.rbegin();
    		all[pos]=v2, mp[v2].insert(pos);//先insert再erase,val==v2且val在末尾时先erase可能erase不到元素。
    		all.pop_back(), mp[v2].erase(all.size());
    
    		return 1;
    	}
    	int getRandom()
    	{
    		return all[rand()%all.size()];
    	}
    };
    RandomizedCollection sol;
    
    int main()
    {
    //	vector<int> v; int x;
    //	while(~scanf("%d",&x)) v.pb(x);
    	printf("%d
    ",sol.insert(1));
    	printf("%d
    ",sol.remove(1));
    	printf("%d
    ",sol.insert(1));
    
    	return 0;
    }
    

    1931. 用三种不同颜色为网格涂色

    前面题太无聊了看看后面的(近期比赛的hard题)
    虽然也很无聊

    /*
    无聊的入门状压。。3^m状压每列颜色。基数是3比较麻烦(取模常数比较大),但是弄成4也麻烦,所以对每个状态预处理一下染色情况。
    然后O(243*243*m)预处理下哪两个状态间可以转移,这样DP的时候就可以少一个m倍常数。
    另外因为m只有5,如果很闲所有的状态间的转移 是可以手推出来的(也可以写个正常DP然后打表出有用的转移,当然纯属无聊)。
    */
    #include <bits/stdc++.h>
    #define gc() getchar()
    using namespace std;
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    class Solution
    {
    public:
    	#define pc putchar
    	#define gc() getchar()
    	#define pb emplace_back
    	#define mod 1000000007
    	#define Mod(x) x>=mod&&(x-=mod)
    	typedef long long LL;
    	const static int N=1e3+5,M=27*9+5;//M=243
    
    	int f[N][M],sta[M][5],S[M],ok[M][M];
    
    	int colorTheGrid(int m, int n)
    	{
    		int lim=1,cnt=0; for(int t=m; t--; lim*=3);
    		for(int ss=0; ss<lim; ++ss)
    		{
    			int las=-1,fg=1;
    			for(int i=0,s=ss,x; i<m; ++i)
    				x=s%3, s/=3, fg=fg&(las!=x), sta[ss][i]=las=x;
    			if(fg) S[++cnt]=ss, f[1][cnt]=1;
    		}
    
    		for(int i=1; i<=cnt; ++i)
    			for(int j=i+1; j<=cnt; ++j)
    			{
    				int s=S[i],s2=S[j],fg=1;
    				for(int k=0; k<m; ++k)
    					if(sta[s][k]==sta[s2][k]) fg=0;
    				fg && (ok[i][j]=ok[j][i]=1);
    			}
    
    		for(int i=1; i<n; ++i)
    			for(int j=1,v; j<=cnt; ++j)
    				if((v=f[i][j]))
    					for(int k=1; k<=cnt; ++k)
    						if(ok[j][k]) f[i+1][k]+=v, Mod(f[i+1][k]);
    
    		LL res=0;
    		for(int i=1; i<=cnt; ++i) res+=f[n][i];
    		return res%mod;
    	}
    };
    Solution sol;
    
    int main()
    {
    //	vector<int> v; int x;
    //	while(~scanf("%d",&x)) v.pb(x);
    	printf("%d
    ",sol.colorTheGrid(read(),read()));
    
    	return 0;
    }
    

    1938. 查询最大基因差

    ??这都什么无聊的题,模板套模板就是能出一场比赛的hard?题目描述也很含糊,我见过的出题人都没这么写题意的。
    这题就 在线 树剖+可持久化Trie(这种是显然,别的解法没想),离线 DFS+Trie。


    ------------------------------------------------------------------------------------------------------------------------
    无心插柳柳成荫才是美丽
    有哪种美好会来自于刻意
    这一生波澜壮阔或是不惊都没问题
    只愿你能够拥抱那种美丽
    ------------------------------------------------------------------------------------------------------------------------
  • 相关阅读:
    2020-2021:时间戳
    全链路压测落地和演进之路
    Socket粘包问题的3种解决方案,最后一种最完美!
    MySQL为Null会导致5个问题,个个致命!
    Maven中pom.xml的packaging类型
    mysql 二进制数据查询
    编写 Dockerfile 生成自定义镜像
    Python自动提取生成博客园年度报告
    [C#] 使用 Excel 和 Math.Net 进行曲线拟合和数据预测
    干货!亲子教育的6个阶段,不妨对照看看,你正处在哪一个阶段?
  • 原文地址:https://www.cnblogs.com/SovietPower/p/15027606.html
Copyright © 2020-2023  润新知