• XVIII Open Cup named after E.V. Pankratiev. GP of Urals


    A. Nutella’s Life

    斜率优化DP显然,CDQ分治后按$a$排序建线段树,每层维护凸包,查询时不断将队首弹出即可。

    时间复杂度$O(nlog^2n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>P;
    const int N=100010,M=262150;
    int n,i,a[N],cb;ll f[N],g[N],w[N],ans;
    int st[M],en[M],tot,q[4000000];
    int H;
    P b[N];
    inline void up(ll&a,ll b){a<b?(a=b):0;}
    inline double pos(int x,int y){return 1.0*(g[x]-g[y])/(y-x);}
    inline void push(int x){
    	while(H<tot&&pos(q[tot-1],q[tot])>pos(q[tot],x))tot--;
    	q[++tot]=x;
    }
    void build(int x,int l,int r){
    	if(l==r){
    		st[x]=en[x]=++tot;
    		q[tot]=b[l].second;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(x<<1,l,mid);
    	build(x<<1|1,mid+1,r);
    	int i=st[x<<1],j=st[x<<1|1];
    	H=st[x]=tot+1;
    	while(i<=en[x<<1]&&j<=en[x<<1|1]){
    		if(q[i]<q[j]){
    			push(q[i++]);
    		}else{
    			push(q[j++]);
    		}
    	}
    	while(i<=en[x<<1])push(q[i++]);
    	while(j<=en[x<<1|1])push(q[j++]);
    	en[x]=tot;
    }
    inline ll cal(int x,int y){return g[y]+2LL*x*y;}
    void ask(int x,int a,int b,int d,int p){
    	if(b<=d){
    		while(st[x]<en[x]&&cal(p,q[st[x]])<cal(p,q[st[x]+1]))st[x]++;
    		if(st[x]<=en[x])up(f[p],cal(p,q[st[x]])+w[p]);
    		return;
    	}
    	int mid=(a+b)>>1;
    	ask(x<<1,a,mid,d,p);
    	if(d>mid)ask(x<<1|1,mid+1,b,d,p);
    }
    void solve(int l,int r){
    	if(l==r){
    		g[l]=f[l]-l-1LL*l*l;
    		up(ans,f[l]-1LL*(n-l)*(n-l+1));
    		return;
    	}
    	int mid=(l+r)>>1,i;
    	solve(l,mid);
    	cb=0;
    	for(i=l;i<=mid;i++)b[++cb]=P(a[i],i);
    	sort(b+1,b+cb+1);
    	tot=0;
    	build(1,1,cb);
    	for(i=mid+1;i<=r;i++){
    		if(a[i]<b[1].first)continue;
    		int t=lower_bound(b+1,b+cb+1,P(a[i],i))-b-1;
    		ask(1,1,cb,t,i);
    	}
    	solve(mid+1,r);
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)scanf("%d",&a[i]),a[i]*=2;
    	ans=-1LL*n*(n+1);
    	for(i=1;i<=n;i++){
    		f[i]=-1LL*(i-1)*i+a[i];
    		w[i]=-1LL*i*i+i+a[i];
    	}
    	solve(1,n);
    	printf("%lld",ans/2);
    }
    

      

    B. Oleg and Data Science

    若$R<Q$,那么显然$mod Q$操作无效,故答案为无穷。

    否则若$lfloorfrac{L}{Q} floor=lfloorfrac{R}{Q} floor$,则答案为$Qlfloorfrac{L}{Q} floor$的因子个数。

    否则答案为$Q$的因子个数。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    LL L, R, Q;
    LL check(LL n)
    {
    	LL rtn = 1;
    	for(LL x = 2; x * x <= n; ++x)if(n % x == 0)
    	{
    		int cnt = 0;
    		while(n % x == 0)
    		{
    			n /= x;
    			++cnt;
    		}
    		rtn *= cnt + 1;
    	}
    	if(n >= 2)rtn *= 2;
    	return rtn;
    }
    LL bf(bool out)
    {
    	int rtn = 0;
    	for(int X = 1; X <= 40; ++X)
    	{	
    		bool flag = 1;
    		for(int S = L; S <= R; ++S)
    		{
    			if(S % Q % X != S % X)
    			{
    				flag = 0;
    				break;
    			}
    		}
    		if(flag)
    		{
    			if(out)printf("%d ", X);
    		}
    		rtn += flag;
    	}
    	if(out)puts("END");
    	return rtn;
    }
    int main()
    {
    	while(~scanf("%lld%lld%lld",&L,&R,&Q))
    	//while(R = rand() % 30 + 1, L = rand() % R + 1, Q = rand() % 30 + 1, true)
    	{
    		if(R<Q)
    		{
    			puts("infinity");
    		}
    		else
    		{
    			//LL ans = check(max(Q, L / Q * Q));
    			LL ans;
    			if(L / Q == R / Q)ans = check(L / Q * Q);
    			else ans = check(Q);
    			printf("%lld
    ", ans);
    			/*
    			if(ans != bf(0))
    			{
    				printf("%lld %lld %lld: %lld %lld
    ", L, R, Q, ans, bf(1));
    				getchar();
    				//while(1);
    			}
    			*/
    		}
    	}
    	return 0;
    }
    
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    C. Christmas Garland

    首先将相邻同色块合并,建立一张图,每个点表示一种颜色的灯,两点间的边表示这两种颜色相邻的有多少个,那么答案为亮着的灯数减去同时亮着的边数。

    将点按照度数大小以$sqrt{m}$为界分成小点和大点,对于每个点维护$w_x$表示周围有多少个小点亮着。

    那么若操作小点,则枚举它所有相连的边,修改其$w$,同时对于相邻的大点计算对答案的贡献。

    若操作大点,则枚举它所有与大点相连的边,计算贡献。

    时间复杂度$O(nsqrt{n})$。

    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef pair<int,int>P;
    const int N=200010;
    int n,ce,_,m,Q,i,j,x,y,have[N],tot,ans,lim;
    int d[N],a[N],f[N],w[N];
    vector<P>g[N],gg[N];
    vector<P>::iterator it;
    struct E{int x,y;}e[N];
    inline bool cmp(const E&a,const E&b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    inline void add(int x,int y,int z){
    	d[x]++;
    	lim++;
    	g[x].push_back(P(y,z));
    }
    inline void addd(int x,int y,int z){
    	if(d[x]>=lim&&d[y]>=lim)gg[x].push_back(P(y,z));
    }
    int main(){
    	scanf("%d%d%d",&_,&m,&Q);
    	while(_--){
    		scanf("%d",&x);
    		if(x!=a[n])a[++n]=x;
    	}
    	for(i=1;i<=n;i++)have[a[i]]++;
    	for(i=1;i<n;i++){
    		x=a[i],y=a[i+1];
    		if(x>y)swap(x,y);
    		e[++ce].x=x;
    		e[ce].y=y;
    	}
    	sort(e+1,e+ce+1,cmp);
    	for(i=1;i<=ce;i=j){
    		for(j=i;j<=ce&&e[i].x==e[j].x&&e[i].y==e[j].y;j++);
    		add(e[i].x,e[i].y,j-i);
    		add(e[i].y,e[i].x,j-i);
    	}
    	lim=sqrt(lim);
    	for(i=1;i<=ce;i=j){
    		for(j=i;j<=ce&&e[i].x==e[j].x&&e[i].y==e[j].y;j++);
    		addd(e[i].x,e[i].y,j-i);
    		addd(e[i].y,e[i].x,j-i);
    	}
    	while(Q--){
    		scanf("%d",&x);
    		if(d[x]<lim){
    			if(f[x]==0){
    				tot+=have[x];
    				ans+=w[x];
    				for(it=g[x].begin();it!=g[x].end();it++){
    					w[it->first]+=it->second;
    					if(d[it->first]>=lim&&f[it->first])ans+=it->second;
    				}
    			}else{
    				tot-=have[x];
    				ans-=w[x];
    				for(it=g[x].begin();it!=g[x].end();it++){
    					w[it->first]-=it->second;
    					if(d[it->first]>=lim&&f[it->first])ans-=it->second;
    				}
    			}
    		}else{
    			if(f[x]==0){
    				tot+=have[x];
    				ans+=w[x];
    				for(it=gg[x].begin();it!=gg[x].end();it++)if(f[it->first])ans+=it->second;
    			}else{
    				tot-=have[x];
    				ans-=w[x];
    				for(it=gg[x].begin();it!=gg[x].end();it++)if(f[it->first])ans-=it->second;
    			}
    		}
    		f[x]^=1;
    		printf("%d
    ",tot-ans);
    	}
    }
    

      

    D. Anna and Lucky Tickets

    问题即统计有多少长度为$n$的回文十进制数字串满足奇数位数位和等于偶数位数位和。

    若$n$是偶数,那么因为回文的性质,左半部分在右半部分奇偶性反转,故奇数位和必定等于偶数位和,故$ans=10^{frac{n}{2}}$。

    若$n$是奇数,那么奇数位要填$[0,9]$,偶数位要填$[-9,0]$,将所有偶数位都加上$9$,再枚举中间的数,则问题转化为统计$sum_{i=1}^n x_i=m,0leq x_ileq 9$的解数。

    考虑容斥,枚举有$k$个$x_i$必定突破了上限,剩下的不管,将上限从$m$中减掉后用隔板法计算,则$ans=sum_{k=0}^n (-1)^kC(n,k)C(m-10k+n-1,n-1)$。

    时间复杂度$O(n)$。

    #include<cstdio>
    const int N=10000010,P=1000000007;
    int n,i,ans,even,odd,all,fac[N],inv[N];
    inline int po(int a,int b){int t=1;for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;return t;}
    inline int C(int n,int m){
      if(n<m)return 0;
      if(n==m)return 1;
      return 1LL*fac[n]*inv[m]%P*inv[n-m]%P;
    }
    int cal(int sum,int n){
      int ret=0;
      for(int i=0;i<=n;i++){
        int t=1LL*C(sum-i*10+n-1,n-1)*C(n,i)%P;
        if(i&1)ret=(ret-t+P)%P;else ret=(ret+t)%P;
      }
      return ret;
    }
    int main(){
      scanf("%d",&n);
      if(n%2==0)return printf("%d",po(10,n/2)),0;
      for(fac[0]=i=1;i<N;i++)fac[i]=1LL*fac[i-1]*i%P;
      for(inv[0]=inv[1]=1,i=2;i<N;i++)inv[i]=1LL*(P-inv[P%i])*(P/i)%P;
      for(i=2;i<N;i++)inv[i]=1LL*inv[i-1]*inv[i]%P;
      even=n/2;
      odd=n-even;
      all=even*9;
      if((n+1)/2%2)odd--;else even--;
      odd/=2;
      even/=2;
      for(i=0;i<10;i++){
        int t=all-i;
        if(t<0||t%2)continue;
        ans=(cal(t/2,odd+even)+ans)%P;
      }
      printf("%d",ans);
    }
    

      

    E. Octopus

    分类大讨论。

    F. Secret Permutation

    首先进行一轮迭代$Q(zero,i,zero)$即可找到$0$的位置。

    将剩下$n-1$个数放入集合$S$,每次从$S$中随机选择两个$x,y$,询问$Q(x,y,zero)$,即可有很大概率排除掉$x$和$y$,期望$frac{n}{2}$次可以得到$1$的位置。

    那么知道$1$之后,不断询问$Q(i,one,one)$即可得到所有数的位置。

    询问次数期望为$2.5nleq 12512$。

    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #include<algorithm>
    using namespace std;
    const int N=5010;
    int n,i,A,B,x,m,q[N],f[N],one,zero;
    inline int ask(int a,int b,int c){
      printf("? %d %d %d
    ",a,b,c);
      fflush(stdout);
      int t;
      scanf("%d",&t);
      return t;
    }
    int main(){
      srand(time(NULL));
      scanf("%d",&n);
      if(n==1){
        puts("! 0");
        fflush(stdout);
        return 0;
      }
      for(i=0;i<n;i++)zero=ask(zero,i,zero);
      for(i=0;i<n;i++)if(i!=zero)q[m++]=i;
      while(m>1){
        A=q[x=rand()%m];
        swap(q[x],q[--m]);
        B=q[x=rand()%m];
        swap(q[x],q[--m]);
        x=ask(A,B,zero);
        if(x==A)q[m++]=B;
        if(x==B)q[m++]=A;
      }
      f[A=one=q[0]]=1;
      for(i=2;i<n;i++)f[A=ask(A,one,one)]=i;
      printf("!");
      for(i=0;i<n;i++)printf(" %d",f[i]);
      fflush(stdout);
    }
    

      

    G. Polygon Rotation

    留坑。

    H. Mikhail’s Problem

    论文题。回文树求出每个回文等差数列消失的位置,树状数组维护,时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N=100010;
    int sz,last,go[N][26],len[N],diff[N],link[N],series_link[N],baby[N];
    int n,m,i,j,k,x,y,f[N],bit[N];
    int ans[N];
    vector<pair<int,int> >poses[N],que[N];
    char s[N];
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline int go_until_pal(int i,int v){
      while(s[i]!=s[i-len[v]-1])v=link[v];
      return v;
    }
    inline pair<vector<int>,vector<int> >add_char(int i){
      last=go_until_pal(i,last);
      int&v=go[last][s[i]-'a'];
      if(v==-1){
        v=sz++;
        len[v]=len[last]+2;
        if(!last)link[v]=1;
        else{
          last=go_until_pal(i,link[last]);
          link[v]=go[last][s[i]-'a'];
        }
        diff[v]=len[v]-len[link[v]];
        if(diff[v]==diff[link[v]]){
          baby[v]=baby[link[v]];
          series_link[v]=series_link[link[v]];
        }else{
          baby[v]=v;
          series_link[v]=link[v];
        }
      }
      last=v;
      pair<vector<int>,vector<int> >ans;
      for(int u=v;u!=1;u=series_link[u]){
        int B=baby[u];
        vector<pair<int,int> >&vec=poses[B];
        int left=i-len[u]+1;
        if(vec.size()&&vec.back().first==left)vec.back().second=len[u];
        else vec.push_back(make_pair(left,len[u]));
        ans.first.push_back(i-len[B]+1);
        if(vec.size()!=1){
          int L=vec[vec.size()-2].first,
              len_=vec[vec.size()-2].second,
              R=L+len_-1,
              L_=R-len[u]+1;
          ans.second.push_back(L_);
        }
        if(vec.size()!=1)if(vec[vec.size()-1].second==vec[vec.size()-2].second){
          vec[vec.size()-2]=vec[vec.size()-1];
          vec.pop_back();
        }
      }
      return ans;
    }
    inline void add(int x,int p){for(f[x]+=p;x<=n;x+=x&-x)bit[x]+=p;}
    inline int ask(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
    int main(){
      scanf("%s%d",s+1,&m);
      n=strlen(s+1);
      sz=2,last=0,len[0]=-1;
      for(i=0;i<=n+5;i++)memset(go[i],-1,sizeof(go[i]));
      for(i=0;i<m;i++){
        read(x),read(y);
        que[y].push_back(make_pair(x,i));
      }
      for(i=1;i<=n;i++){
        pair<vector<int>,vector<int> >vec=add_char(i);
        vector<int>adding=vec.first,deleting=vec.second; 
        for(j=0;j<deleting.size();j++){
          if(!f[k=deleting[j]])continue;
          add(k,-1);
        }
        for(j=0;j<adding.size();j++){
          if(f[k=adding[j]]==1)continue;
          add(k,1);
        }
        for(j=0;j<que[i].size();j++)ans[que[i][j].second]=sz-2-ask(que[i][j].first-1);
      }
      for(i=0;i<m;i++)printf("%d
    ",ans[i]);
    }
    

      

    I. Rat-O-Matic

    若$A$包含$B$,则$B$的半径不超过$A$的一半,故扫描线将包含关系建树后,树高不超过$O(log R)$。

    对于每个字符串,枚举所有后缀,将长度$O(log R)$的前缀插入字典树,即可完成询问。

    J. Readability

    贪心,求出每个数的活动区间,扫描线的时候将最优的那个数填下来即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    int a[N], b[N], c[N];
    int v[2];
    int w[2][N];
    int P(int o, int id)
    {
    	return id * 2 - o;
    }
    struct A
    {
    	int pos, val;
    };
    bool gorgt(A a, A b)
    {
    	if(a.pos != b.pos)return a.pos < b.pos;
    	return a.val > b.val;
    }
    bool golft(A a, A b)
    {
    	if(a.pos != b.pos)return a.pos > b.pos;
    	return a.val > b.val;
    }
    void GORGT(int st, int ed, int val, int o, int aimo, int b[])
    {
    	vector<A>vt;
    	for(int i = st; ; i += val)
    	{
    		vt.push_back({w[o][i], 1});
    		vt.push_back({P(aimo,i), -1});
    		if(i == ed)break;
    	}
    	sort(vt.begin(), vt.end(), gorgt);
    	multiset<int>sot;
    	for(auto it : vt)
    	{
    		if(it.val == 1)
    		{
    			sot.insert(a[it.pos]);
    		}
    		else
    		{
    			b[it.pos] = *sot.begin();
    			sot.erase(sot.begin());
    		}
    	}
    }
    void GOLFT(int st, int ed, int val, int o, int aimo, int b[])
    {
    	vector<A>vt;
    	for(int i = st; ; i += val)
    	{
    		vt.push_back({w[o][i], 1});
    		vt.push_back({P(aimo,i), -1});
    		if(i == ed)break;
    	}
    	sort(vt.begin(), vt.end(), golft);
    	multiset<int>sot;
    	for(auto it : vt)
    	{
    		if(it.val == 1)
    		{
    			sot.insert(a[it.pos]);
    		}
    		else
    		{
    			b[it.pos] = *--sot.end();
    			sot.erase(--sot.end());
    		}
    	}
    }
    LL solve(int o, int aimo, int b[])
    {
    	LL rtn = 0;
    	//try to check every num
    	for(int i = 1; i <= v[o]; ++i)
    	{
    		int l = w[o][i];	//start pos
    		int r = P(aimo, i);	//end pos
    		rtn += abs(l - r);
    		if(l == r)
    		{
    			b[r] = a[l];
    		}
    		else if(l < r)
    		{
    			int p = i;
    			while(p < v[o])
    			{
    				int ll = w[o][p + 1];
    				int rr = P(aimo, p + 1);
    				if(ll <= r)
    				{
    					r = rr;
    					++p;
    					rtn += abs(ll - rr);
    				}
    				else break;
    			}
    			GORGT(i, p, 1, o, aimo, b);
    			i = p;
    		}
    		else
    		{
                swap(l, r);
    			int p = i;
    			while(p < v[o])
    			{
    				int ll = w[o][p + 1];
    				int rr = P(aimo, p + 1);
    				swap(ll, rr);
    				if(ll <= r)
    				{
    					r = rr;
    					++p;
    					rtn += abs(ll - rr);
    				}
    				else break;
    			}
    			GOLFT(i, p, 1, o, aimo, b);
    			i = p;
    		}
    	}
    	return rtn;
    }
    void print(int b[])
    {
    	for(int i = 1; i <= n; ++i)
    	{
    		printf("%d%c", b[i], i == n ? '
    ' : ' ');
    	}
    }
    bool small(int b[], int c[])
    {
        for(int i = 1; i <= n; ++i)
        {
            if(b[i] > c[i])return 0;
            if(b[i] < c[i])return 1;
        }
        return 0;
    }
    int p[N];
    int d[N], ansd[N];
    LL bf()
    {
        int ans = 1e9;
        for(int i = 1; i <= n; ++i)p[i] = i;
        do
        {
            int tmp = 0;
            bool flag = 1;
            for(int i = 1; i <= n; ++i)
            {
                tmp += abs(p[i] - i);
                d[i] = a[p[i]];
                if(i >= 2 && d[i] % 2 == d[i - 1] % 2)flag = 0;
            }
            if(flag)
            {
                if(tmp < ans || tmp == ans && small(d, ansd))
                {
                    ans = tmp;
                    for(int i = 1; i <= n; ++i)ansd[i] = d[i];
                }
            }
        }while(next_permutation(p + 1, p + n + 1));
    }
    int main()
    {
    	while(~scanf("%d",&n))
    	//while(n = rand() % 9 + 1, true)
    	{
    	    //for(int i = 1; i <= n; ++i)a[i] = i; random_shuffle(a + 1, a + n + 1);
    	    //printf("A: ");print(a);
    		v[0] = v[1] = 0;
    		for(int i = 1; i <= n; ++i)
    		{
    			scanf("%d", &a[i]);
    			if(a[i] & 1)
    			{
    				w[1][++v[1]] = i;
    			}
    			else
    			{
    				w[0][++v[0]] = i;
    			}
    		}
    	    //bf();
    		if(n & 1)
    		{
    			//puts("n & 1");
    
    			//偶 奇 偶
    			if(v[0] > v[1])
    			{
    				solve(0, 1, b);
    				solve(1, 0, b);
    			}
    			//奇 偶 奇
    			else
    			{
    				solve(1, 1, b);
    				solve(0, 0, b);
    			}
    			print(b);
    			/*
                if(small(ansd, b))
                {
                    puts("NO");
                    print(ansd);
                    getchar();
                }
                */
    		}
    		else
    		{
                //ans1 偶 奇
                LL ans1 = solve(0, 1, b) + solve(1, 0, b);
                //ans2 ji ou
                LL ans2 = solve(1, 1, c) + solve(0, 0, c);
                if(ans1 < ans2)
                {
                    print(b);
                    /*
                    if(small(ansd, b))
                    {
                        puts("NO");
                        print(ansd);
                        getchar();
                    }
                    */
                }
                else if(ans1 > ans2)
                {
                    print(c);
                    /*
                    if(small(ansd, c))
                    {
                        puts("NO");
                        print(ansd);
                        getchar();
                    }
                    */
                }
                else
                {
                    if(small(b, c))
                    {
                        print(b);
                        /*
                        if(small(ansd, b))
                        {
                            puts("NO");
                            print(ansd);
                            getchar();
                        }
                        */
                    }
                    else
                    {
                        print(c);
                        /*
                        if(small(ansd, c))
                        {
                            puts("NO");
                            print(ansd);
                            getchar();
                        }
                        */
                    }
                }
    		}
    	}
    	return 0;
    }
    
    /*
    【trick&&吐槽】
    4
    1 3 2 4
    
    4
    3 1 4 2
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    K. Robotobor

    BFS出$d[i][j][x][y]$表示从$(i,j)$到$(x,y)$的最短回文路线。

    第二次BFS出$f[i][j]$表示从$(i,j)$到终点最少需要多少条长度不超过$100$的回文路线。

    时间复杂度$O(n^4)$。

    #include<cstdio>
    const int N=55;
    int n,m,i,j,x,y;
    char a[N][N];
    int d[N][N][N][N],f[N][N];
    char q[N*N*N*N][4];
    int h,t;
    inline void ext(int A,int B,int C,int D,int w){
    	if(A<1||A>n||B<1||B>m)return;
    	if(a[A][B]=='#')return;
    	if(C<1||C>n||D<1||D>m)return;
    	if(a[C][D]=='#')return;
    	if(~d[A][B][C][D])return;
    	q[++t][0]=A;
    	q[t][1]=B;
    	q[t][2]=C;
    	q[t][3]=D;
    	d[A][B][C][D]=w;
    }
    inline void up(int x,int y,int w){
    	if(~f[x][y])return;
    	q[++t][0]=x;
    	q[t][1]=y;
    	f[x][y]=w;
    }
    inline int abs(int x){return x>0?x:-x;}
    void print(int A,int B,int C,int D){
    	if(A==C&&B==D)return;
    	if(abs(A-C)+abs(B-D)==1){
    		if(A+1==C)putchar('D');
    		if(A-1==C)putchar('U');
    		if(B+1==D)putchar('R');
    		if(B-1==D)putchar('L');
    		return;
    	}
    	if(~d[A][B-1][C][D+1]&&d[A][B-1][C][D+1]+2==d[A][B][C][D]){
    		putchar('L');
    		print(A,B-1,C,D+1);
    		putchar('L');
    		return;
    	}
    	if(~d[A][B+1][C][D-1]&&d[A][B+1][C][D-1]+2==d[A][B][C][D]){
    		putchar('R');
    		print(A,B+1,C,D-1);
    		putchar('R');
    		return;
    	}
    	if(~d[A-1][B][C+1][D]&&d[A-1][B][C+1][D]+2==d[A][B][C][D]){
    		putchar('U');
    		print(A-1,B,C+1,D);
    		putchar('U');
    		return;
    	}
    	if(~d[A+1][B][C-1][D]&&d[A+1][B][C-1][D]+2==d[A][B][C][D]){
    		putchar('D');
    		print(A+1,B,C-1,D);
    		putchar('D');
    		return;
    	}
    	puts("Error");
    	while(1);
    }
    void show(int x,int y){
    	while(f[x][y]){
    		bool flag=0;
    		for(i=1;i<=n;i++)for(j=1;j<=m;j++){
    			if(flag)break;
    			if(~d[x][y][i][j]&&d[x][y][i][j]<=100&&f[i][j]+1==f[x][y]){
    				print(x,y,i,j);
    				puts("");
    				x=i,y=j;
    				flag=1;
    				break;
    			}
    		}
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=n;i++)scanf("%s",a[i]+1);
    	for(i=0;i<=n+1;i++)for(j=0;j<=m+1;j++)for(x=0;x<=n+1;x++)for(y=0;y<=m+1;y++){
    		d[i][j][x][y]=-1;
    	}
    	h=1,t=0;
    	for(i=1;i<=n;i++)for(j=1;j<=m;j++)ext(i,j,i,j,0);
    	for(i=1;i<=n;i++)for(j=1;j<=m;j++){
    		ext(i,j,i+1,j,1);
    		ext(i,j,i-1,j,1);
    		ext(i,j,i,j-1,1);
    		ext(i,j,i,j+1,1);
    	}
    	while(h<=t){
    		int A=q[h][0],B=q[h][1],C=q[h][2],D=q[h][3];
    		h++;
    		int w=d[A][B][C][D]+2;
    		//D
    		ext(A-1,B,C+1,D,w);
    		//U
    		ext(A+1,B,C-1,D,w);
    		//L
    		ext(A,B+1,C,D-1,w);
    		//R
    		ext(A,B-1,C,D+1,w);
    	}
    	h=1,t=0;
    	for(i=1;i<=n;i++)for(j=1;j<=m;j++)f[i][j]=-1;
    	for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(a[i][j]=='F')up(i,j,0);
    	while(h<=t){
    		int A=q[h][0],B=q[h][1];
    		h++;
    		int w=f[A][B]+1;
    		for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(~d[i][j][A][B]&&d[i][j][A][B]<=100)up(i,j,w);
    	}
    	for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(a[i][j]=='S'){
    		if(f[i][j]<0)return puts("-1"),0;
    		printf("%d
    ",f[i][j]);
    		show(i,j);
    		return 0;
    	}
    }
    

      

  • 相关阅读:
    关于面向对象
    javaScrip字符串(String)相关
    http协议了解
    javascript-回归原生基础
    Java每日一面(Part1:计算机网络)[19/11/25]
    Java每日一面(Part1:计算机网络)[19/11/13]
    Java每日一面(Part1:计算机网络)[19/11/02]
    Java每日一面(Part1:计算机网络)[19/10/21]
    tomcat8 到idea控制台和servlet乱码问题
    Java每日一面(Part1:计算机网络)[19/10/14]
  • 原文地址:https://www.cnblogs.com/clrs97/p/8667455.html
Copyright © 2020-2023  润新知