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官方题解。
咕咕咕。