ARC143 题解
作者:互联网
太弱小了,仅 A 的一题还是在后辈 ly 的指导下才成功的。\(\sout{我被单调队列了}\)
\(\sout{tnnd,刚才忘记保存了重新写一遍。}\)
T1 Three Integers
题意
有三个数 \(A,B,C\) , 有两种操作
Operation 1:选择两个数并 \(-1\)
Operation 2:选择三个数并 \(-1\)
使得这三个数全变成 \(0\) ,如果不行请输出 \(-1\) 。
做时思路
因为肯定 Operation 2 肯定更优一点,所以对于大数据肯定有很多 Operation 2 。然后猜大数据是小数据的 Operation 2 的变化过来的。
但是错了
题解
首先说一个推论:
每次操作肯定操作到最大值。
为什么?思考一下什么时候不会操作到最大值。就是对于 Operation 1 操作最小的两个数。显然不优。
ly 的推断办法:
假如说 \(A ,B, C\) 已经排好顺序了。根据 \(\sout{相对论}\) 只有一种操作,就是选一个数 \(+1\) 这样的话肯定不可能给 \(C\) 加。
代码
#include <bits/stdc++.h>
#define debug puts("I love Newhanser forever!!!!!");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
t=0; register char ch=getchar(); register int fflag=1;
while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
const int MAXN=800;
long long A,B,C,ans;
long long min(long long A,long long B){return (A<B)?A:B;}
int main(){
read(A,B,C);
long long a[]={A,B,C};
sort(a,a+3);
if(a[0]+a[1]<a[2]) puts("-1");
else cout<<a[2]<<endl;
return 0;
}
//Welcome back,Chtholly.
T2 Counting Grids
赛时猜到正解,代码写错了,误以为是错解。
题意
就是一个 \(n\times n\) 的网格,你要把 \(1-n\times n\) 的数字填进去。然后不存在任意一个数是行里的最小值也是列里的最大值。
赛时思路 & 正解
考试的时候想到从容斥定理的角度考虑,因为如果正着填的话会遇到很多限制条件,如果反着填的话限制条件比较多。
既然反着做,那么把行里的最小值和列里的最大值叫做坏的元素。
这里给出一个结论:
只可能有一个坏的元素
为什么,非常的简单,但是昨天太拉了,没有想着去证明。
明显有两个方格矛盾了。
那怎么推柿子呢?
明显发现,每个格子都是等价的,所以这里假设第一个格子就是坏的元素。这里对答案的乘法贡献是 \(n^2\)
假如说第一个格子填的是 \(x\) ,那么这样的话行里面可以填的数字数量就是 \(\dbinom{n^2-x}{n-1}\) ,列里可以填的数字数量就是 \(\dbinom{x-1}{n-1}\) 。然后行里面可以交换位置,列里面可以交换位置。先把到目前柿子列出来 :
\[n^2 \times ((n-1)!)^2 \times \sum\limits _{i=1}^{n^2} \dbinom{n^2-i}{n-1} \dbinom{i-1}{n-1} \]不要让战斗停下来,我们还少了一点东西,就是除了我们填完的这一行一列我们还有一些东西可以交换,就是剩下的。他们对答案的贡献是 \((n^2-2*n+1)!\)
答案就是
\[((n-1)^2)! \times (n!)^2 \times \sum\limits _{i=1}^{n^2} \dbinom{n^2-i}{n-1} \dbinom{i-1}{n-1} \]\(n^2\) 和 \((n-1)^2\) 合起来了。
因为 \(\dbinom{n}{k} = \frac{n!}{(n-k)!k!}\) 组合数还是比较大的, exgcd 又比较的 ex ,所以这里用欧拉定理求逆元啦。
因为预处理了逆元等等东西,所以总的时间复杂度是 \(\mathbb{O}(n^2)\) 。
代码
#include <bits/stdc++.h>
#define debug puts("I love Newhanser forever!!!!!");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
t=0; register char ch=getchar(); register int fflag=1;
while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
const int MAXN=250005;
const long long mod=998244353;
typedef long long ll;
ll n,ans=1,A[MAXN],B[MAXN],inv[MAXN],p=1,c=1;
ll fac[MAXN];
ll quick_pow(ll x,ll y){
ll res=1;
while(y){
if(y&1) res=(x*res)%mod;
x=(x*x)%mod;
y>>=1;
}
return res;
}
ll C(ll n,ll k){
if(k==0) return 1;
if(k>n) return 0;
return fac[n]*inv[n-k]%mod*inv[k]%mod;
}
int main(){
read(n);
fac[0]=inv[0]=1;
for(int i=1;i<=n*n;++i){
fac[i]=fac[i-1]*i%mod;
inv[i]=quick_pow(fac[i],mod-2)%mod;
}
p=fac[(n-1)*(n-1)]%mod*fac[n]%mod*fac[n]%mod;
ans=fac[n*n];
for(int i=n;i<=n*n-n+1;++i) ans=(ans-p*C(n*n-i,n-1)%mod*C(i-1,n-1)%mod+2*mod)%mod;
cout<<ans<<endl;
return 0;
}
//Welcome back,Chtholly.
标签:dbinom,read,题解,ll,long,times,ARC143,Operation 来源: https://www.cnblogs.com/Mercury-City/p/16417431.html