North American Southeast Regional 2019 (Div 1) 题解

A
搜索即可,每个位置可能的值有2个,然后高位反向递推之后就跟低位一样了。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<string>
#include<set>

#define maxn 30
#define maxh 13

using
		namespace
					std;

int n;
char s_[maxn];
int s[maxn];
int a[maxn];

int sq[10]={0,1,4,9,6,5,6,9,4,1};
int inv[10]={-1,1,-1,7,-1,-1,-1,3,-1,9};

bool judge(int pos,int b){
	
	if(b==1){
		
		return n==1;
	}
	
	if(pos>=2*b-1){
		
		return 2*b-1>=n;
	}
	
	if(pos>=b){
		
		int tem=0;
		
		for(int i=pos-b+1;i<b;i++){
			
			tem=(tem+a[i]*a[pos-i]%10)%10;
		}
		
		if(tem==s[pos]){
			
			//cout<<"++"<<pos<<endl;
			
			return judge(pos+1,b);
		}
		else{
			
			//cout<<"--"<<pos<<' '<<tem<<' '<<s[pos]<<endl;
			
			return false;
		}
	}
	else{
		
		int tem=0;
		
		for(int i=1;i<pos;i++){
			
			tem=(tem+a[i]*a[pos-i]%10)%10;
		}
		
		for(int i=0;i<10;i++){
			
			if((2*a[0]*i%10+tem)%10==s[pos]){
				
				a[pos]=i;
				//cout<<"++"<<pos<<' '<<i<<endl;
				
				if(judge(pos+1,b)) return true;
			}
			else{
				
				//cout<<"--"<<pos<<' '<<2*a[0]*i%10<<' '<<s[pos]<<endl;
			}
		}
		
		return false;
	}
	
	return false;
}

set<string> sk;

bool check(int b){
	
	bool has=false;
	
	for(int i=0;i<10;i++){
		
		if(sq[i]==s[0]){
			
			a[0]=i;
			
			//cout<<"+"<<a[0]<<endl;
			
			if(judge(1,b)){
				
				string kotae;
				
				for(int j=0;j<b;j++){
					
					kotae+=a[j]+'0';
				}
				
				reverse(kotae.begin(),kotae.end());
				
				sk.insert(kotae);
				
				has=true;
			}
		}
	}
	
	return has;
}

signed main(){
	
	scanf("%s",s_);
	
	n=strlen(s_);
	
	for(int i=0;i<n;i++){
		
		s[i]=s_[i]-'0';
	}
	
	reverse(s,s+n);
	
	for(int i=1;i<=maxh;i++){
		
		//cout<<"len="<<i<<endl;
		
		if(check(i)){
			
			break;
		}
	}
	
	if(sk.empty()){
		
		cout<<-1<<endl;
		goto end;
	}
	
	cout<<*sk.begin()<<endl;
	
end:
	return EOF+1;
}
/*
1208425200945084748250041
*/

B
线段树维护cache的部分,操作1就是区间修改,操作2就是单点查询,维护每一段区间属于哪个数组的什么位置,且版本为多少。
这样得到所有询问对应的数组的版本,然后再顺序扫一遍维护所有数组,碰到查询直接得到答案。
复杂度 O ( q l o g n + ∑ k ) O(qlogn+\sum k) O(qlogn+k)

#include <iostream>
#include <algorithm>
#define ls (node << 1)
#define rs (node << 1 | 1)
#define mod 256
struct change {
	int data, ver, from;
};
const int N = 5e5+7;
struct Node {
	int l, r;
	bool c;
	change val;
}tree[N<<2];
void f(int node, change& k) {
	tree[node].val = k;
	tree[node].c = 1;
}
void push_down(int node) {
	if (tree[node].c) {
		f(ls, tree[node].val);
		f(rs, tree[node].val);
		tree[node].c = 0;
	}
}
void build(int node, int L, int R) {
	tree[node].l = L, tree[node].r = R;
	if (L==R) {
		return;
	}
	int mid = L+R>>1;
	build(ls, L, mid);
	build(rs, mid+1, R);
}
void modify(int node, int L, int R, change& k) {
	if (tree[node].l>=L && tree[node].r<=R) {
		f(node, k);
		return ;
	}
	if (tree[node].l>R || tree[node].r<L) return ;
	push_down(node);
	modify(ls, L, R, k), modify(rs, L, R, k);
}
change query(int node, int x) {
	if (tree[node].l==x && tree[node].r==x) return tree[node].val;
	push_down(node);
	int mid = tree[node].l+tree[node].r>>1;
	if (x<=mid) return query(ls, x);
	return query(rs, x);
}

struct Node_ {
	int l, r, val, add;
	Node_() {
		l = r = val = add = 0;
	}
};
class segTree {
public:
	Node_ * tree;
	~segTree() {
		delete[] tree;
	}
	void pre(int n, int *nums) {
		tree = new Node_[n<<2];
		this->build(1, 1, n, nums);
	}

	void f(int node, int k) {
		tree[node].add = (tree[node].add+k)%mod;
		tree[node].val = (tree[node].val+k)%mod;
	}
	void push_down(int node) {
		if (tree[node].add) {
			this->f(ls, tree[node].add);
			this->f(rs, tree[node].add);
			tree[node].add = 0;
		}
	}
	void build(int node, int L, int R, int *nums) {
		tree[node].l = L, tree[node].r = R;
		if (L==R) {
			tree[node].val = nums[L];return;
		}
		int mid = L+R>>1;
		this->build(ls, L, mid, nums);
		this->build(rs, mid+1, R, nums);
	}
	void modify(int node, int L, int R, int k) {
		if (tree[node].l>=L && tree[node].r<=R) {
			this->f(node, k);
			return ;
		}
		if (tree[node].l>R || tree[node].r<L) return ;
		this->push_down(node);
		this->modify(ls, L, R, k), this->modify(rs, L, R, k);
	}
	int query(int node, int x) {
		if (tree[node].l==x && tree[node].r==x) return tree[node].val;
		this->push_down(node);
		int mid = tree[node].l+tree[node].r>>1;
		if (x<=mid) return this->query(ls, x);
		return this->query(rs, x);
	}
};

int len[N], nums[N];
segTree alldata[N];
// int cnt[N];
int ans[N], ans_cnt;
struct Q {
	int data, ver, pos, i;
	bool operator<(const Q& q) const {
		return ver<q.ver;
	}
} qs[N];
struct OP {
	int data, l, r;
}ops[N];
int main() {
	int n, m, q;
	std::cin >> n >> m >> q;
	build(1, 1, n);

	for (int i = 1; i<=m; ++i) {
		std::cin >> len[i];
		for (int j = 1; j<=len[i]; ++j) std::cin >> nums[j];
		alldata[i].pre(len[i], nums);
	}
	int _cnt = 0;
	for (int i = 1, &cnt = _cnt, op, x, l, r, p; i<=q; ++i) {
		std::cin >> op;
		if (op==1) {
			std::cin >> x >> p;
			change tmp = {x, cnt, p};
			modify(1, p, p+len[x]-1, tmp);
		} else if (op==2) {
			std::cin >> p;
			change tmp = query(1, p);
			qs[++ans_cnt].data = tmp.data;
			qs[ans_cnt].ver = tmp.ver;
			qs[ans_cnt].pos = p-tmp.from+1;
			qs[ans_cnt].i = ans_cnt;
		} else {
			std::cin >> x >> l >> r;
			ops[++cnt].data = x;
			ops[cnt].l = l;
			ops[cnt].r = r;
		};
	}
	std::sort(qs+1, qs+1+ans_cnt);

	for (int i = 0, t = 1; i<=_cnt && t<=ans_cnt; ++i) {
		if (i!=0) {
			alldata[ops[i].data].modify(1, ops[i].l, ops[i].r, 1);
		}
		while (t<=ans_cnt && qs[t].ver<=i) {
			// std::cout << qs[t].data << "\n";
			if (qs[t].data==0) {
				ans[qs[t].i] = 0;
				++t;
				continue;
			}
			ans[qs[t].i] = alldata[qs[t].data].query(1, qs[t].pos);
			t++;
		}
	}
	for (int i = 1; i<=ans_cnt; ++i) {
		std::cout << ans[i] << "\n";
	}
	return 0;
}

C
数组 a a a为初始值, b b b为每一轮的值。
这题如果 a i % b i = 0 a_i\%b_i=0 ai%bi=0,则需要 a i + + a_i++ ai++,而给定的是 b i b_i bi,因此,维护每个数字 k k k的倍数在数组 a a a中的值,有多个都需要维护,如果重复则只需要1个即可。这样遍历 b b b,每次将 m a p [ b [ i ] ] map[b[i]] map[b[i]]中的所有值取出并+1即可,注意这可能需要关联更细其他位置的map。
复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=300020;
const int maxn=300010;
int T,n,m;
int a[N],b[N],cnt[N];
vector<int> fac[N];
set<int> mul[N];//对于b,存储所有a
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		cnt[a[i]]++;
	}
	for(int i=1;i<=m;i++){
		cin>>b[i];
	}
	ll ans=0;
	for(int i=1;i<=maxn;i++){
		for(int j=i;j<=maxn;j+=i){
			fac[j].pb(i);//存储所有因子
		}
	}
	for(int i=1;i<=maxn;i++){
		if(cnt[i]){
			for(auto j:fac[i]){
				mul[j].insert(i);
			}
		}
	}
	for(int i=1;i<=m;i++){
		int t=b[i];
		while(mul[t].size()){//存储了所有t的倍数的a[i],均需要+1
			
			auto tmp=*mul[t].begin();
			//cout<<"|||"<<i<<' '<<tmp<<' '<<cnt[tmp]<<'\n';
			mul[t].erase(mul[t].begin());
			ans+=cnt[tmp];
			cnt[tmp+1]+=cnt[tmp];
			cnt[tmp]=0;
			for(auto j:fac[tmp]){
				mul[j].erase(tmp);
			}
			for(auto j:fac[tmp+1]){//转移到tmp+1
				mul[j].insert(tmp+1);
			}
		}
	}
	cout<<ans<<'\n';
}

D
将可以一次操作得到的字符串对连边,显然是一个二分图,求二分图的最大独立点集,只需要求最大匹配即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f3f3f3f3f
#define mod 1000000007 
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"No\n","Yes\n"};
const int N=200010;
int n,m,s,t,cnt=1;//从2开始,保证相反边只有低位不同 
int to[N],nxt[N],head[N],now[N];//now:当前弧优化 
ll wei[N],dis[N],ans,gnum;
void add(int u,int v,ll w)
{
	to[++cnt]=v;
	wei[cnt]=w;
	nxt[cnt]=head[u];
	head[u]=cnt;
	//反向边 
	to[++cnt]=u;
	wei[cnt]=0;
	nxt[cnt]=head[v];
	head[v]=cnt;
}
bool bfs()//分层 
{
	for(int i=0;i<=gnum;i++) dis[i]=inf;
	dis[s]=1;now[s]=head[s];
	queue<int> q;
	q.push(s);
	bool flag=0;
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int i=head[x];i;i=nxt[i]){
			int j=to[i];
			if(wei[i]&&dis[j]==inf){
				q.push(j);
				now[j]=head[j];
				dis[j]=dis[x]+1;
				if(j==t) return 1;
			}
		}
	}
	return 0;
}
ll dfs(ll x,ll sum)//当前节点,以及当前节点的总流量 
{
	if(x==t) return sum;
	ll out=0;//out为结果
	for(int i=now[x];i&&sum;i=nxt[i]){
		now[x]=i;
		int j=to[i];
		if(wei[i]>0&&dis[j]==dis[x]+1){
			ll k=dfs(j,min(sum,wei[i]));//递归j
			if(k==0) dis[j]=inf;//剪枝,去除不可能的点
			wei[i]-=k;
			wei[i^1]+=k;
			out+=k;
			sum-=k;
		}
	}
	return out;//总流量 
}

vector<int> vec[510];
int len;
string str[510];
map<string,int> mp;
int vis[510];
int c[510];
void dfs(int x)
{
	vis[x]=1;
	for(auto j:vec[x]){
		if(vis[j]) assert(c[x]^c[j]);
		else{
			c[j]=c[x]^1;
			dfs(j);
		}
	}
	return;
}
signed main()
{
	cin>>n;
	gnum=2*n+2;
	s=2*n+1,t=2*n+2;
	for(int i=1;i<=n;i++){
		cin>>str[i];
		mp[str[i]]=i;
	}
	len=str[1].length();
	for(int i=1;i<=n;i++){
		for(int j1=0;j1<len;j1++){
			for(int j2=j1+1;j2<len;j2++){
				string tmp=str[i];
				swap(tmp[j1],tmp[j2]);
				if(mp.find(tmp)!=mp.end()){
					int x=mp[tmp];
					if(x>i){
						vec[i].pb(x);
						vec[x].pb(i);
					}
				}
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			dfs(i);
		}
	}
	for(int i=1;i<=n;i++){
		for(auto j:vec[i]){
			if(c[i]==0&&c[j]==1){
				add(i,j,1);
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(c[i]==0) add(s,i,1);
		else add(i,t,1);
	}
	while(bfs()){
		ans+=dfs(s,inf);
	}
	cout<<n-ans<<'\n';
}

E
主要思想就是贪心+容斥。从前往后贪心当前位置放数字 i i i是否可能,利用容斥计算后面的总方案数。由于会溢出导致WA,因此用py。

import math

a=[0 for i in range(52)]
vis=[False for i in range(52)]

def Stagger(n,x):

    ans=0

    for i in range(0,x+1):
        if i%2==0:
            ans+=math.comb(x,i)*math.factorial(n-i)
        else:
            ans-=math.comb(x,i)*math.factorial(n-i)

    return ans



def cal_bac(pos,val):

    cnt=0

    for i in range(pos+1,n+1):
        if not vis[i] and i!=val:
            cnt+=1
    return cnt

def cal_cont(pos,val,x):

    x=n-m-pos+x
    num=n-pos
    bac=cal_bac(pos,val)

    if x-n+pos+bac<0 or x-n+pos+bac>bac:
        return 0
    
    ans=math.comb(bac,x-n+pos+bac)*Stagger(x,x-n+pos+bac)

    return ans
    

n,m,k=map(int,input().split())

if n==1 and m==1 and k==1:
    print(1)
    exit()

if m==n-1:
    print(-1)
    exit()

now=0
stone=0
    
for pos in range(1,n+1):
    
    for i in range(1,n+1):

        if not vis[i]:

            if i==pos and stone==m:

                continue

            cont=cal_cont(pos,i,stone+(i==pos))

            if now+cont<k:
                now+=cont
            else:
                a[pos]=i
                if i==pos:
                    stone+=1
                vis[i]=True
                break

for i in range(1,n+1):
    if not vis[i]:
        print(-1)
        exit()

if now!=k-1:
    print(-1)
    exit()

for i in range(1,n+1):
    print(a[i],end=' ')

F
离散差分。
每个点的贡献是以 a a a为中心,附近的 t / s t/s t/s弧度的范围,特判弧度 > p i >pi >pi的情形。然后由于是环形的,还需要特判是否经过0,经过的话分成两半即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pi 3.1415926535898
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=200010;
int T,n,m;
double cur;//斜率
double sum=0;//当前的加速值
map<double,double> mp;//位于每一处,的斜率偏移量;
void add(double t,double s,double a)
{
	if(t/s>=pi){//全部覆盖
		if(a<pi){
			mp[a]-=2*s;
			mp[a+pi]+=2*s;
			cur+=s;
		}
		else{
			mp[a-pi]+=2*s;
			mp[a]-=2*s;
			cur-=s;
		}
	}
	else{//部分覆盖
		//区间[a-t/s,a]增加,[a,a+t/s]减小
		if(a-t/s<0){//分成两半
			cur+=s;
			mp[a]-=2*s;
			mp[a-t/s+2*pi]+=s;
			mp[a+t/s]+=s;
		}
		else if(a+t/s>2*pi){
			cur-=s;
			mp[a+t/s-2*pi]+=s;
			mp[a-t/s]+=s;
			mp[a]-=2*s;
		}
		else{
			mp[a]-=2*s;
			mp[a-t/s]+=s;
			mp[a+t/s]+=s;
		}
	}
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++){
		double t,s,a;
		cin>>t>>s>>a;
		add(t,s,a);
		sum+=max(0.0,max(t-s*a,t-s*(2*pi-a)));
	}
	double ans=sum;
	double pre=0;
	for(auto it:mp){
		double tpre=it.first;
		double tsub=it.second;
		sum+=cur*(tpre-pre);
		pre=tpre;
		ans=max(ans,sum);
		cur+=tsub;
	}
	printf("%.10lf",ans);
}

G
当前点 u u u子树中的任意点 v v v,若满足 a u < = a v a_u<=a_v au<=av,则可以贡献,因此利用dfs序,将子树转化为区间查询,然后将大小关系转化为按照大小来操作线段树即可。注意大小相等应该先更新下面的节点。
线段树区间维护最大值和区间和即可。

#include <iostream>
#include <vector>
#include <algorithm>
#define ls (node << 1)
#define rs (node << 1 | 1)
#define mod 11092019
const int N =1e6+7;
using ll = long long;
// #define int ll
std::vector<int> son[N];
int dep[N], val[N], dfn[N], siz[N], pos[N], cnt;
struct Node {
	int l, r, mx;
	ll cnt;
	Node(): l(0), r(0), mx(0), cnt(0){}
	Node operator+(const Node& n) const {
		Node res;
		res.l = l, res.r = n.r;
		if (mx==n.mx) {
			res.mx = mx;
			res.cnt = (cnt+n.cnt)%mod;
		} else if (mx>n.mx) {
			res.mx = mx;
			res.cnt = cnt;
		} else {
			res.mx = n.mx;
			res.cnt = n.cnt;
		}
		return res;
	}
}tree[N<<2];

void push_up(int node) {
	tree[node] = tree[ls]+tree[rs];
}

void build(int node, int L, int R) {
	tree[node].l = L, tree[node].r = R;
	if (L==R) {
		return ;
	}
	int mid = L+R>>1;
	build(ls, L, mid);
	build(rs, mid+1, R);
}
void modify(int node, int x, int k, ll _cnt) {
	if (tree[node].l==x && tree[node].r==x) {
		tree[node].cnt = _cnt;
		tree[node].mx = k;
		return;
	}
	if (tree[node].l>x || tree[node].r<x) return;
	modify(ls, x, k, _cnt);
	modify(rs, x, k, _cnt);
	push_up(node);
}
Node query_mx(int node, int L, int R) { 
	if (tree[node].l>=L && tree[node].r<=R) {
		return tree[node];
	}
	if (tree[node].l>R || tree[node].r<L) return tree[0];
	return query_mx(ls, L, R)+query_mx(rs, L, R);
}


void dfs(int node, int depth) {
	dep[node] = depth;
	dfn[++cnt] = node;
	siz[node] = 1;
	pos[node] = cnt;
	for (int &i:son[node]) {
		dfs(i, depth+1);
		siz[node]+=siz[i];
	}
}
int op[N];
signed main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	int n;
	std::cin >> n;
	for (int i = 1; i<=n; ++i) std::cin >> val[i], op[i] = i;
	for (int i = 2, p; i<=n; ++i) {
		std::cin >> p;
		son[p].push_back(i);
	}
	dfs(1, 0);
	build(1, 1, n);
	std::sort(op+1, op+1+n, [&](int x, int y)->bool {
		if (val[x]==val[y]) return dep[x]>dep[y];
		return val[x]>val[y];
	} );
	int ans = 0;
	ll ans_c = 0;
	for (int j = 1; j<=n; ++j) {
		int i = op[j];
		int l = pos[i]+1, r = pos[i]+siz[i]-1;
		int mx_tmp;
		ll cnt_tmp;
		if (l>r) {
			mx_tmp = 1;
			cnt_tmp = 1;
		} else {
			Node tmp = query_mx(1, l, r);
			mx_tmp = tmp.mx+1, cnt_tmp = tmp.cnt;
			if (mx_tmp==1) cnt_tmp = 1;
		}
		modify(1, pos[i], mx_tmp, cnt_tmp);
		// std::cout << mx_tmp << "---\n";
		if (ans<mx_tmp) {
			ans = mx_tmp;
			ans_c = cnt_tmp;
		} else if (ans==mx_tmp) (ans_c+=cnt_tmp)%=mod;
	}
	std::cout << ans << " " << ans_c;
	return 0;
}


H
签到

#include <iostream>
#include <set>

int main() {
	std::string s, t;
	std::cin >> s >> t;
	std::set<std::string> st;
	int n = t.size();
	for (char &i:t) {
		char c = i;
		for (char &j:s) {
			if (j==c) continue;
			i = j;
			st.insert(t);
		}
		i = c;
	}
	for (int i = 0; i<=n; ++i) {
		if (i!=n) st.insert(t.substr(0, i)+t.substr(i+1, n-i-1));
		for (char &j:s) {
			st.insert(t.substr(0, i)+j+t.substr(i, n-i));
		}
	}
	for (auto &i:st) {
		std::cout << i << "\n";
	}

	return 0;
}

I
搜索带点的连通块数量,并特判样例1那样都被包住但是算1个连通块的数量即可。

#include<iostream>

#define maxn 1003
#define maxm 1003

using
		namespace
					std;

int n,m;
char s[maxn][maxm];
bool vis[maxn][maxm];

const int dx[8]={1,1,1,0,-1,-1,-1,0};
const int dy[8]={-1,0,1,1,1,0,-1,-1};

int kotae;

bool dfs(int x,int y){
	
	if(x<0||y<0||x==n||y==m) return false;
	if(s[x][y]!='.') return true;
	if(vis[x][y]) return true;
	vis[x][y]=true;
	
	bool ans=true;
	
	for(int i=0;i<8;i++){
		
		if(abs(dx[i])+abs(dy[i])==1){
			
			ans&=dfs(x+dx[i],y+dy[i]);
		}
		else{
			
			if(x+dx[i]<0||x+dx[i]==n||y+dy[i]<0||y+dy[i]==m) continue;
			
			if(dx[i]^dy[i]){
				
				if(s[x][y+dy[i]]=='/'&&s[x+dx[i]][y]=='/'){
					
					ans&=dfs(x+dx[i],y+dy[i]);
				}
			}
			else{
				
				if(s[x][y+dy[i]]=='\\'&&s[x+dx[i]][y]=='\\'){
					
					ans&=dfs(x+dx[i],y+dy[i]);
				}
			}
		}
	}
	
	return ans;
}

signed main(){
	
	scanf("%d %d",&n,&m);
	
	for(int i=0;i<n;i++){
		
		scanf("%s",s[i]);
	}
	
	for(int i=0;i<n;i++){
		
		for(int j=0;j<m;j++){
			
			if(s[i][j]=='.'&&!vis[i][j]){
				
				kotae+=dfs(i,j);
			}
		}
	}
	
	for(int i=0;i<n-1;i++){
		
		for(int j=0;j<m-1;j++){
			
			kotae+=(s[i][j]=='/'&&s[i][j+1]=='\\'&&s[i+1][j]=='\\'&&s[i+1][j+1]=='/');
		}
	}
	
	printf("%d\n",kotae);
	
end:
	return EOF+1;
}

J
类似单调栈维护即可,若更小则尝试t掉,如果后面该数不出现就不能t

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
typedef pair<int,int> pir;
string sstr[]={"NO\n","YES\n"};
const int N=200010;
int T,n,k;
int a[N];
int last[N];
int vis[N];
int stkn[N];//数值
int stkp[N];//和位置
int in[N];//标记是否在stk中
int top=-1;
vector<int> ans;
signed main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=n;i>=1;i--){
		if(vis[a[i]]==0){//某个数最后一次出现
			last[a[i]]=i;
			vis[a[i]]=1;
		}
	}
	memset(vis,0,sizeof(vis));
	int p=1,q;
	for(int i=1;i<=n;i++){
		if(in[a[i]]) continue;//已经在其中
		while(top>=0&&i<=last[stkn[top]]&&a[i]<stkn[top]) in[stkn[top]]=0,top--;//后面还有该数字才能t掉
		top++;
		stkn[top]=a[i];
		stkp[top]=i;
		in[a[i]]=1;
	}
	for(int i=0;i<=top;i++) cout<<stkn[i]<<' ';
}

K
unsolved
极角序,每对点 ( i , j ) (i,j) (i,j)表示当前中心为 i i i且转到了 j j j,其后继确定,为 ( j , k ) (j,k) (j,k),这样建图,显然会形成若干环,维护每个环中每个点出现的次数,以及整个环转过的弧度(可能有180,360或者其他)。
因为题目给了一定能转回去,虽然不知道为啥
复杂度 O ( n 2 l o g n ) O(n^2logn) O(n2logn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值