noip62

T1

考场想法:直接暴力20pts滚粗了。

然而有50pts,不过好多人都切了

正解:

求出在模 \(n\) 意义下的前缀和,那么前缀和的取值范围为 \([0,n-1]\) ,一共有 \(n\) 个数,而前缀和从 \(0\) 算到 \(n\) ,一共有 \(n+1\) 个数,所以一定有两个在模 \(n\) 意义下是相等的,设其为 \(i,j\) ,那就说明在 \([i+1,j]\) 这一段中的数的和是能够被 \(n\) 整除。同时也说明这个问题是一定有解的。

所以求个前缀和即可。

T2

考场想法:直接如果求出来的 \(A\) 相邻的有两个相同的,那肯定选第一个不选第二个,那直接乱写就行了然而是假的

好吧,是我读题出问题了,但仍有可怜我的10pts。

正解:

首先一个简单的式子,\(ans=\max(xam-n\times2-1,0)\) ,这里的 \(xam\) 指的是个数的最多的书的个数。

那么问题就是求这个 \(xam\) 。直接用桶会爆空间。

考虑换一种方法。

在生成序列的同时,拿两个指针 \(id,cnt\) 去扫它,如果 \(id==a_{now}\)\(cnt++\) 否则 \(cnt--\) ,如果当前 \(cnt==0\) 了,那就把 \(id\) 设为 \(a_{now}\)\(cnt=1\)

最后再扫一遍,求一下最后的 \(id\) 的出现次数,求出来的就是 \(xam\)

T3

正解:

建议直接去看uoj官方题解,挺详细的。

Code
#include<cstdio>
#include<cctype>
#define MAX 403
#define re register
#define int long long
const int mod = 998244353;
namespace some
{
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			bool w=0; s=0; char ch=getchar();
			while(!isdigit(ch)){ w|=ch=='-'; ch=getchar(); }
			while(isdigit(ch)){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }
			return s=w?-s:s,*this;
		}
	}cin;
	bool flag;
	int n,k,ans = 1;
	int d[MAX][MAX];
}using namespace some;
namespace simple
{
	auto check = []() -> bool
	{
		for(re int l=1; l<=n; l++)
		{
			if(d[l][l]!=0)
			{ return 0; }
			for(re int r=l+1; r<=n; r++)
			{
				if(d[l][r]!=d[r][l]||d[l][r]>k)
				{ return 0; }
				for(re int mid=1; mid<=n; mid++)
				{
					if(l==mid||r==mid)
					{ continue ; }
					if(d[l][r]>d[l][mid]+d[mid][r])
					{ return 0; }
				}
			}
		}
		return 1;
	};
};
namespace OMA
{
	int f[MAX],g[MAX];
	int c[MAX],inv[MAX];
	auto quickpow = [](int a,int b,int res = 1) -> int
	{
		while(b)
		{
			if(b&1)
			{ res = res*a%mod; }
			a = a*a%mod,b >>= 1;
		}
		return res;
	};
	auto C = [](int n,int m) -> int { return c[n]*inv[n-m]%mod*inv[m]%mod; };
	int fa[MAX],size[MAX];
	int find(int x) { return x!=fa[x]?fa[x] = find(fa[x]):fa[x]; }
	auto merge = [](int x,int y) -> void { int r1 = find(x),r2 = find(y); if(r1!=r2){ fa[r2] = r1,size[r1] += size[r2]; } };
	auto main = []() -> signed
	{
		freopen("c.in","r",stdin); freopen("c.out","w",stdout);
		cin >> n >> k;
		for(re int i=1; i<=n; i++)
		{
			fa[i] = i,size[i] = 1;
			for(re int j=1; j<=n; j++)
			{ cin >> d[i][j]; }
		}
		if(!simple::check()) { printf("0\n"); return 0; }
		c[0] = inv[0] = 1;
		for(re int i=1; i<=n; i++)
		{
			c[i] = c[i-1]*i%mod;
			for(re int j=i+1; j<=n; j++)
			{ if(!d[i][j]){ merge(i,j); } }
		}
		inv[n] = quickpow(c[n],mod-2);
		for(re int i=n-1; i; i--)
		{ inv[i] = inv[i+1]*(i+1)%mod; }
		for(re int i=1; i<=n; i++)
		{
			f[i] = g[i] = quickpow(k+1,(i-1)*i/2);
			for(re int j=1; j<=i-1; j++)
			{ f[i] = (f[i]-f[j]*g[i-j]%mod*C(i-1,j-1)%mod*quickpow(k,j*(i-j))%mod+mod)%mod; }
			if(i!=find(i)) { continue ; }
			for(re int j=i+1; j<=n; j++)
			{
				if(i==find(j)||j!=find(j)) { continue ; }
				flag = false;
				for(re int mid=1; mid<=n; mid++)
				{
					if(i==mid||j==mid||i==find(mid)||j==find(mid)) { continue ; }
					if(d[i][j]==d[i][mid]+d[mid][j]) { flag = true; break ; }
				}
				ans = ans*(quickpow(k-d[i][j]+1,size[i]*size[j])-(flag?0:quickpow(k-d[i][j],size[i]*size[j]))+mod)%mod;
			}
		}
		for(re int i=1; i<=n; i++)
		{ ans = ans*f[size[i]]%mod; }
		printf("%lld\n",ans);
		return 0;
	};
}
signed main()
{ return OMA::main(); }

T4

考场想法:\(next\_permutation\) yyds!

10pts收场....

正解:

同样建议去看uoj官方题解。

咕咕咕。

posted @ 2021-09-27 21:39  -OMA-  阅读(81)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end