D - Lis on Circle Gym - 102441D (LIS + 线段树)
There are nn people at the round gaming table. Each of them has a set of cards. Every card contains some number xx. Players make turns consecutively, one after another, starting from the player number 1. A player in his turn can either skip his turn (to pass), or put (and leave on the table) a card with a number that is strictly greater than the previously played last number. No more than kk players in a row can pass the turn. All players know the numbers written on the other players cards and always play optimally. Help gamblers to assemble an increasing sequence of maximum length.
Input
The first line contains two numbers nn and kk — the number of players and the maximum possible amount of turn skipping in a row.
The next nn lines contain the description of the cards players have in their hands. The first number in the mimi is the number of cards the current player has in his hand. The following space separated miminumbers represent the written on the cards numbers xx.
Output
In the first line print the single number — the length of the maximum sequence. In the next lines print two space separated numbers: the player index number and the number written on the card he played. If several solutions exist, output any of them.
Example
3 1 4 1 10 12 20 2 11 21 4 3 5 15 22
9 1 1 3 3 1 10 2 11 1 12 3 15 1 20 2 21 3 22
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define ll long long #define ull unsigned long long #define met(a, b) memset(a, b, sizeof(a)) #define rep(i, a, b) for(int i = a; i <= b; i++) #define bep(i, a, b) for(int i = a; i >= b; i--) #define lowbit(x) (x&(-x)) #define MID (l + r) / 2 #define ls pos*2 #define rs pos*2+1 #define pb push_back #define ios() ios::sync_with_stdio(0) using namespace std; typedef pair<int,int>pi; const int maxn = 1e5 + 1010; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f; const ll mod = 1e9 + 7; struct node{ int id,x; bool operator < (const node & w)const{ return x < w.x || (x == w.x && id < w.id); } }arr[maxn]; pi dp[maxn],tree[maxn<<2]; void pushup(int rt){ tree[rt] = max(tree[rt*2],tree[rt*2+1]); } void build(int l,int r,int rt){ if(l == r){ tree[rt] = pi(0,-1); return ; } int mid = (l + r) / 2; build(l,mid,rt*2); build(mid + 1,r,rt*2+1); pushup(rt); } pi query(int L,int R,int l,int r,int rt){//询问[L,R]内长度最长的上升子序列节点 if(L > R)return pi(0,-1); if(L <= l && r <= R){ return tree[rt]; } int mid = (l + r) / 2; pi ans = pi(0,-1); if(L <= mid)ans = max(ans,query(L,R,l,mid,rt*2)); if(R > mid)ans = max(ans,query(L,R,mid+1,r,rt*2+1)); return ans; } void update(int pos,pi val,int l,int r,int rt){//pos位置更改最优值(和自身取最优值) if(l == r){ tree[rt] = max(tree[rt],val); return ; } int mid = (l + r) / 2; if(pos <= mid)update(pos,val,l,mid,rt*2); else update(pos,val,mid+1,r,rt*2+1); pushup(rt); } void dfs(int u,int dep){//dfs寻找路径,dp[u].second 代表下一个下标是几 if(u == -1){ cout << dep << endl; return ; } dfs(dp[u].second,dep+1); cout << arr[u].id << ' ' << arr[u].x << endl; } int main() { int n,k,top = 0; cin >> n >> k; build(1,n,1); rep(i,1,n){ int m; cin >> m; rep(j,1,m){ int x; cin >> x; arr[++top] = (node){i,x}; } } sort(arr+1,arr+1+top); int i; for(i = 1;i <= top;){ for(int j = i;j <= top;j++){//一个值的数据有多个的话,处理完,先不更新,因为题目保证严格递增 if(arr[i].x != arr[j].x)break; int id = arr[j].id; int pos = ((id - k - 2) % n + n) % n + 1;//最多可跳过k个,这个推一下就好了~ if(pos < id)dp[j] = query(pos,id-1,1,n,1); else dp[j] = max(query(pos,n,1,n,1),query(1,id-1,1,n,1)); } int j; for(j = i;j <= top;j++){ if(arr[i].x != arr[j].x)break; if(dp[j].first == 0 && arr[j].id > k + 1)continue;//第一个人特判 dp[j].first++;//以j为结尾的最长上升子序列加1 int pos = arr[j].id; update(pos,pi(dp[j].first,j),1,n,1);//更新最优值 } i = j; } int ans = 0,rt = 0; for(int i = 1;i <= top;i++){ if(dp[i].first > ans){ ans = dp[i].first; rt = i; } } if(rt == 0)cout << 0 << endl; else dfs(rt,0); return 0; } /* 3 0 3 1 2 3 3 1 2 1 4 1 2 3 2 */