XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix

Claris發表於2018-03-12

A. Accommodation Plan

對於已知的$K$個點,離它們距離都不超過$L$的點在樹上是一個連通塊,考慮在每種方案對應的離$1$最近的點統計。

即對於每個點$x$,統計離它距離不超過$L$的點數$call[x]$,再減去離它和它父親距離都不超過$L$的點數$cext[x]$,然後用組合數計算方案數。

對於$call[x]$可以通過點分治+排序雙指標$O(n\log^2n)$統計。

對於$cext[x]$,注意到$cext[x]=call[x]-csub[x]$,其中$csub[x]$表示$x$點子樹中深度在$(dep[x]+L-dis(x,fa[x]),dep[x]+L]$的點數,二維數點問題,掃描線+樹狀陣列維護即可$O(n\log n)$統計。

時間複雜度$O(n\log^2n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100010,P=1000000007;
int n,K,L,i,j,x,y,z,fac[N],inv[N],ans;
int g[N],nxt[N<<1],v[N<<1],w[N<<1],ok[N<<1],ed,son[N],f[N],all,now;
int call[N],csub[N],cnt,bit[N],st[N],en[N],dfn;
struct E{ll x;int y;E(){}E(ll _x,int _y){x=_x,y=_y;}}e[N],q[N<<1];
inline bool cmp(const E&a,const E&b){return a.x<b.x;}
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;ok[ed]=1;}
void findroot(int x,int y){
  son[x]=1,f[x]=0;
  for(int i=g[x];i;i=nxt[i])if(v[i]!=y&&ok[i]){
    findroot(v[i],x);
    son[x]+=son[v[i]];
    if(son[v[i]]>f[x])f[x]=son[v[i]];
  }
  if(all-son[x]>f[x])f[x]=all-son[x];
  if(f[x]<f[now])now=x;
}
void dfs(int x,int y,ll z){
  e[++cnt]=E(z,x);
  for(int i=g[x];i;i=nxt[i])if(v[i]!=y&&ok[i])dfs(v[i],x,z+w[i]);
}
inline void cal(int p){
  sort(e+1,e+cnt+1,cmp);
  int i,j;
  for(i=1,j=cnt;i<=cnt;i++){
    while(j&&e[i].x+e[j].x>L)j--;
    call[e[i].y]+=p*j;
  }
}
void solve(int x){
  int i;
  cnt=0;
  dfs(x,0,0);
  cal(1);
  for(i=g[x];i;i=nxt[i])if(ok[i]){
    cnt=0;
    dfs(v[i],x,w[i]);
    cal(-1);
  }
  for(i=g[x];i;i=nxt[i])if(ok[i]){
    ok[i^1]=0;
    f[0]=all=son[v[i]];
    findroot(v[i],now=0);
    solve(now);
  }
}
void dfs2(int x,int y,ll z){
  st[x]=++dfn;
  e[x]=E(z,x);
  q[++cnt]=E(z+L,x);
  for(int i=g[x];i;i=nxt[i])if(v[i]!=y){
    q[++cnt]=E(z+L,-v[i]);
    dfs2(v[i],x,z+w[i]);
  }
  en[x]=dfn;
}
inline void ins(int x){for(;x<=n;x+=x&-x)bit[x]++;}
inline int ask(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
inline int C(int n,int m){return n<m?0:1LL*fac[n]*inv[m]%P*inv[n-m]%P;}
int main(){
  scanf("%d%d%d",&n,&K,&L);
  for(ed=i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
  f[0]=all=n;findroot(1,now=0);solve(now);
  dfs2(1,cnt=0,0);
  sort(e+1,e+n+1,cmp);
  sort(q+1,q+cnt+1,cmp);
  for(i=j=1;i<=cnt;i++){
    while(j<=n&&e[j].x<=q[i].x)ins(st[e[j++].y]);
    x=q[i].y;
    if(x<0)x=-x;
    y=ask(en[x])-ask(st[x]-1);
    if(q[i].y>0)csub[x]+=y;else csub[x]-=y;
  }
  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;
  for(i=1;i<=n;i++)ans=((ans+C(call[i],K))%P+P-C(call[i]-csub[i],K))%P;
  ans=1LL*ans*fac[K]%P;
  printf("%d",ans);
}

  

B. Card Game

列舉$n$的所有約數判斷。

#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, m;
int a[N];
map<int, int> mop;

int main()
{
    while(~ scanf("%d%d", &n, &m)){
        mop.clear();
        int A = 0, B = 0;
        for(int i = 1; i <= m; i ++){
            scanf("%d", &a[i]);
            gmax(A, a[i]);
            mop[a[i]] ++;
            gmax(B, mop[a[i]]);
        }
        //printf("%d %d\n", A, B);
        int ans = 0;
        for(int i = 1; i * i <= n; i ++){
            if(n % i == 0){
                int j = n / i;
                if(i >= A && j >= B){
                    ans ++;
                    //printf("i j %d %d\n", i, j);
                }
                if(i != j && i >= B && j >= A){
                    ans ++;

                    //printf("j i %d %d\n", j, i);
                }
            }
        }
        if(ans != 1) puts("NO");
        else puts("YES");
    }
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

C. The Most Expensive Gift

若迴圈節長度為$1$,則答案下界為$\frac{n^2}{9}$,經過分析可得迴圈節長度超過$8$都是不優的。

暴力搜尋所有長度不超過$8$的串作為迴圈節,然後貪心匹配計算長度即可。

時間複雜度$O(3^8n)$。

#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 = 10010, 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;
char s[N];
char a[N];
int ans;
int len;
int check()
{
	int pos = 0;
	int now = 0;
	for(int i = 0; i < n; ++i)
	{
		if(s[i] == a[pos])
		{
			++now;
			pos = pos + 1;
			if(pos == len)pos = 0;
		}
	}
	int LEN = now / len * len;
	return LEN * LEN / len;
}
int main()
{
	while(~scanf("%d%s",&n, s))
	{
		ans = 0;
		for(len = 1; ; ++len)
		{
			int bst = n * n / len;
			if(bst <= ans)break;
			
			int top = 1;
			for(int i = 0; i < len; ++i)
			{
				a[i] = 'a';
				top *= 3;
			}
			for(int tim = 1; tim <= top; ++tim)
			{
				gmax(ans, check());
				++a[len - 1];
				int pos = len - 1;
				while(a[pos] == 'd')
				{
					a[pos] = 'a';
					++a[--pos];
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

D. Cut the Cake

兩個維度獨立,對於一維問題,將所有位置排序,每隔$k$個切一刀即可。

#include<cstdio>
const int N=300;
int n,m,k,i,j,dx,dy,cntx,cnty,cx[N],cy[N],qx[N],qy[N];char a[N][N];
inline int cal(int xl,int xr,int yl,int yr){
	int t=0;
	for(int i=xl;i<=xr;i++)for(int j=yl;j<=yr;j++)if(a[i][j]=='1')t++;
	return t;
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<=n;i++)scanf("%s",a[i]+1);
	for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(a[i][j]=='1'){
		dx++;
		if(dx%k==0&&dx<k*k)cx[i]=1;
	}
	for(j=1;j<=m;j++)for(i=1;i<=n;i++)if(a[i][j]=='1'){
		dy++;
		if(dy%k==0&&dy<k*k)cy[j]=1;
	}
	for(i=1;i<n;i++)if(cx[i])qx[++cntx]=i;
	for(i=1;i<m;i++)if(cy[i])qy[++cnty]=i;
	if(cntx!=k-1||cnty!=k-1)return puts("NO"),0;
	qx[cntx+1]=n;
	qy[cnty+1]=m;
	for(i=1;i<=cntx;i++)for(j=1;j<=cnty;j++)if(cal(qx[i-1]+1,qx[i],qy[j-1]+1,qy[j])!=1)return puts("NO"),0;
	puts("YES");
	for(i=1;i<=cntx;i++)printf("%d ",qx[i]);puts("");
	for(i=1;i<=cnty;i++)printf("%d ",qy[i]);puts("");
}

  

E. Message

留坑。

 

F. Bad Word

若整個串不是迴文串,則答案顯然為$1$。

若整個串形如$aaaaa$、$aabaa$、$ababa$,則無解。

否則答案必然是$2$。

#include<cstdio>
const int N=200010;
int n,i;char a[N];
int main(){
	scanf("%d%s",&n,a+1);
	for(i=1;i<=n;i++)if(a[i]!=a[n-i+1])break;
	if(i<=n)return puts("1"),0;
	for(i=1;i<=n;i++)if(a[i]!=a[1])break;
	if(i>n)return puts("-1"),0;
	if(n%2==0)return puts("2"),0;
	for(i=1;i<=n/2;i++)if(a[i]!=a[1])break;
	if(i>n/2)return puts("-1"),0;
	for(i=1;i<=n;i++){
		if(i>2&&a[i]!=a[i-2])break;
	}
	if(i>n)return puts("-1"),0;
	puts("2");
}

  

G. Zenyk, Marichka and Interesting Game

首先將所有石子數都模$A+B$,並剔除小於$\min(A,B)$的堆。

若$A=B$,則根據奇偶性判斷即可。

若$A>B$,列舉$A$的第一步行動,然後交換先後手,轉化為$A<B$的問題。

若$A<B$:

  • 若$n=0$,則先手必敗。
  • 若一步之內可以造出只能$A$拿的堆,即存在石子數$<B$或者$\geq 2A$的堆,那麼$A$可以利用這一堆來控制先後手,從而必勝。
  • 否則任何一堆兩人都只能恰好拿一次,故根據$n$的奇偶性判斷即可。
#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
typedef pair<int,int>P;
const int N=100010;
int n,m,A,B,x,a[N];set<P>T;
int work(int A,int B){
	if(T.size()==0)return 0;
	set<P>::iterator x=T.begin();
	if(x->first<B)return 1;
	x=T.end();
	x--;
	if(x->first>=A*2)return 1;
	return T.size()%2;
}
int solve(){
	int i,ans=0;
	if(A==B){
		for(i=1;i<=m;i++)ans=(ans+a[i]/A)%2;
		return ans;
	}
	if(A<B)return work(A,B);
	for(i=1;i<=m;i++)if(a[i]>=A){
		T.erase(P(a[i],i));
		int t=a[i]-A;
		if(t<A&&t<B)t=0;
		if(t)T.insert(P(t,i));
		if(!work(B,A))return 1;
		if(t)T.erase(P(t,i));
		T.insert(P(a[i],i));
	}
	return 0;
}
int main(){
	scanf("%d%d%d",&n,&A,&B);
	while(n--){
		scanf("%d",&x);
		x%=A+B;
		if(x<A&&x<B)continue;
		a[++m]=x;
		T.insert(P(x,m));
	}
	puts(solve()?"Zenyk":"Marichka");
}

  

H. Frog Jumping

貪心用代價最小的若干個青蛙去貪心地走路線。

#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, m, K, D;
int c[N];
LL sum[N];
int a[N];
int main()
{
	while(~scanf("%d%d%d%d",&n, &m, &K, &D))
	{
		for(int i = 1; i <= m; ++i)scanf("%d", &c[i]);
		sort(c + 1, c + m + 1);
		for(int i = 1; i <= m; ++i)
		{
			sum[i] = sum[i - 1] + c[i];
		}
		set<int>sot;
		for(int i = 1; i <= K; ++i)
		{
			scanf("%d", &a[i]);
			sot.insert(a[i]);
		}
		sort(a + 1, a + K + 1);
		int way = 0;
		int pos = 1;
		sot.insert(n);
		while(!sot.empty())
		{
			auto it = sot.upper_bound(pos + D);
			
			//can't reach it
			if(it == sot.begin())
			{
				break;
			}
			
			--it;
			pos = *it;
			//
			//printf("pos = %d\n", pos);
			//
			if(pos == n)
			{
				++way;
				if(way >= m)break;
				pos = 1;
			}
			else sot.erase(it);
		}
		//
		//printf("Here: way = %d\n", way);
		//
		LL ans = 0;
		if(way == 0)
		{
			a[0] = 1; a[K + 1] = n;
			for(int i = 1; i <= K + 1; ++i)
			{
				int dis = a[i] - a[i - 1];
				if(dis > D)
				{
					ans += c[1];
				}
			}
			ans += sum[m] - sum[1];
		}
		else
		{
			ans = sum[m - way];
		}
		printf("%lld\n", ans);
	}
	return 0;
}

/*
【trick&&吐槽】
10 2 3 3
4 7
4 8 7

10 2 2 3
4 7
9 5

【題意】


【分析】


【時間複雜度&&優化】


*/

  

I. Slot Machine

按照最壞情況模擬即可。

#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;
vector<int>vt[N];
int a[N];
set< pair<int,int> >sot[N];
int main()
{
	while(~scanf("%d",&n))
	{
		int ANS = inf;
		for(int i = 0; i < N; ++i)sot[i].clear();
		for(int i = 1; i <= n; ++i)
		{
			vt[i].clear();
			int g;
			scanf("%d", &g);
			for(int j = 1; j <= g; ++j)
			{
				int x;
				scanf("%d", &x);
				vt[i].push_back(x);
			}
			sort(vt[i].begin(), vt[i].end());
			int col = 0;
			for(int j = 0; j < g; ++j)
			{
				if(j == g - 1 || vt[i][j] != vt[i][j + 1])
				{
					++col;
				}
			}
			int cnt = 0;
			for(int j = 0; j < g; ++j)
			{
				++cnt;
				if(j == g - 1 || vt[i][j] != vt[i][j + 1])
				{
				    if(cnt > 1)gmin(ANS, col + 1);
					sot[ vt[i][j] ].insert( {col, i} );
					cnt = 0;
				}
			}
		}
		for(int i = 1; i <= n; ++i)
		{
			int g = vt[i].size();
			int cnt = 0;
			int col = 0;
			for(int j = 0; j < g; ++j)
			{
				++cnt;
				if(j == g - 1 || vt[i][j] != vt[i][j + 1])
				{
					a[++col] = inf;
					for(auto it : sot[ vt[i][j] ])
					{
						int bl = it.second;
						if(bl == i && cnt == 1)continue;
						a[col] = it.first + 1;
						break;
					}
					cnt = 0;
				}
			}
			sort(a + 1, a + col + 1);
			reverse(a + 1, a + col + 1);
			for(int j = 1; j <= col; ++j)
			{
				//printf("(%d %d): %d\n", i, j, a[j]);
				gmin(ANS, a[j] + j - 1);
			}
		}
		printf("%d\n", ANS);
	}
	return 0;
}

/*
【trick&&吐槽】
7
4 1 2 3 4
1 1
1 2
1 3
1 4
7 4 7 4 4 7 7 4
1 5


5
5 1 2 5 3 4
5 1 2 5 6 7
5 1 2 5 8 9
5 1 2 5 10 11
20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

2
5 1 2 3 4 5
1 1


1
5 1 2 3 1 2

【題意】


【分析】


【時間複雜度&&優化】


*/

  

J. Half is Good

注意到邊權在$[0,2^{62})$內隨機,故最後$8$位影響排序結果的概率非常小,可以忽略。

還剩$54$位,分成最高的$22$位和後面$32$位,將最高的$22$位相同的邊分組,每組內部排序,每組數量都不多。

然後直接求最小生成樹即可。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef unsigned int U;
typedef unsigned long long ll;
const int N=10000010,M=(1<<22)+5;
int n,m,i,u,v,f[N],have,goal;
int g[M],nxt[N],q[1000000];
U e[N][3],ans[N/32+10];
U s;
ll w;
inline bool cmp(int x,int y){return e[x][2]<e[y][2];}
inline U getnxt(){
s ^= s << 13;
s ^= s >> 17;
s ^= s << 5;
return s;
}
int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
inline void merge(int x){
	int a=e[x][0],b=e[x][1];
	//printf("merge %d %d\n",a,b);
	if(F(a)!=F(b)){
		have++;
		ans[x>>5]|=1U<<(x&31);
		f[f[a]]=f[b];
	}
}
inline void solve(int x){
	if(g[x]<0)return;
	if(nxt[g[x]]<0){
		merge(g[x]);
		return;
	}
	int cnt=0;
	for(int i=g[x];~i;i=nxt[i])q[cnt++]=i;
	sort(q,q+cnt,cmp);
	for(int i=0;i<cnt;i++)merge(q[i]);
}
int main(){
	scanf("%d%d%u",&n,&m,&s);
	goal=(n-1)/2+1;
	goal=min(goal,n-1);
	U mask=~0U;
	for(i=0;i<M;i++)g[i]=-1;
	for(i=0;i<m;i++){
		u=getnxt()%n;
		v=getnxt()%n;
		w=getnxt()>>2;
		w=w*getnxt();
		w>>=8;
		e[i][0]=u;
		e[i][1]=v;
		e[i][2]=w&mask;
		w>>=32;
		nxt[i]=g[w];
		g[w]=i;
		//printf("%d %d %llu\n",u,v,w);
	}
	for(i=0;i<n;i++)f[i]=i;
	for(i=0;i<M&&have<goal;i++)solve(i);
	m=(m-1)/32;
	for(i=0;i<=m;i++)printf("%u ",ans[i]);
}

  

K. Dance

留坑。

 

L. Impress Her

對於一個$A\times B$的包圍矩形,因為四連通,至少消耗$A+B$個點,故直接列舉每個矩形內部所有點的時間複雜度為$O(n^3)$。

對於每個點記錄其所屬矩形,對於每個矩形$x$,列舉內部所有點,檢查$x$是否包含該點所屬矩形即可,用時間戳來$O(1)$判重。

#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 = 505, M = 1e6 + 10, 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, m;
int a[N][N];
bool vis[M];
bool vs[N][N];
int dfn[M];
int ymin[M];
int ymax[M];
int xmin[M];
int xmax[M];

const int dy[4] = {-1,0,0,1};
const int dx[4] = {0,-1,1,0};
void dfs(int y, int x)
{
	if(vs[y][x])return;
	vs[y][x] = 1;
	gmin(ymin[a[y][x]], y);
	gmax(ymax[a[y][x]], y);
	gmin(xmin[a[y][x]], x);
	gmax(xmax[a[y][x]], x);
	for(int k = 0; k < 4; ++k)
	{
		int yy = y + dy[k];
		int xx = x + dx[k];
		if(a[yy][xx] == a[y][x])
		{
			dfs(yy, xx);
		}
	}
}
int main()
{
	while(~scanf("%d%d",&n, &m))
	{
		for(int i = 1; i <= n; ++i)
		{
			for(int j = 1; j <= m; ++j)
			{
				scanf("%d", &a[i][j]);
			}
		}
		MS(vis, 0);
		MS(vs,0);
		MS(ymin, 63);
		MS(ymax, 0);
		MS(xmin, 63);
		MS(xmax, 0);
		for(int i = 1; i <= n; ++i)
		{
			for(int j = 1; j <= m; ++j)
			{
				if(!vis[ a[i][j] ])
				{
					vis[ a[i][j] ] = 1;
					dfs(i, j);
				}
			}
		}
		MS(dfn, 0);
		int tim = 0;
		int ans = 0;
		for(int i = 1; i <= n; ++i)
		{
			for(int j = 1; j <= m; ++j)
			{
				int col = a[i][j];
				if(vis[col])
				{
					vis[col] = 0;
					++tim;
					for(int y = ymin[col]; y <= ymax[col]; ++y)
					{
						for(int x = xmin[col]; x <= xmax[col]; ++x)
						{
							int c = a[y][x];
							if(c != col && dfn[c] != tim
							 && ymin[c] >= ymin[col]
							 && ymax[c] <= ymax[col]
							 && xmin[c] >= xmin[col]
							 && xmax[c] <= xmax[col]
							 )
							{
								dfn[c] = tim;
								++ans;
							}
						}
					}
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

/*
【trick&&吐槽】


【題意】


【分析】


【時間複雜度&&優化】


*/

  

相關文章