zoukankan      html  css  js  c++  java
  • 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。


    ------------------------------------------------------------------------------------------------------------------------
    无心插柳柳成荫才是美丽
    有哪种美好会来自于刻意
    这一生波澜壮阔或是不惊都没问题
    只愿你能够拥抱那种美丽
    ------------------------------------------------------------------------------------------------------------------------
  • 相关阅读:
    Sql Server 2008卸载后再次安装一直报错
    listbox 报错 Cannot have multiple items selected when the SelectionMode is Single.
    Sql Server 2008修改Sa密码
    学习正则表达式
    Sql Server 查询第30条数据到第40条记录数
    Sql Server 复制表
    Sql 常见面试题
    Sql Server 简单查询 异步服务器更新语句
    jQuery stop()用法以及案例展示
    CSS3打造不断旋转的CD封面
  • 原文地址:https://www.cnblogs.com/SovietPower/p/15027606.html
Copyright © 2011-2022 走看看