今天又考试了…
T1几乎全班满分,我才30分,我打的暴力都有70分…
后面的题一分没拿,实在是失策…
垃圾话时间结束,下面开始看T1:
暴力70分的做法是枚举每一个工作人员
i
i
i,再枚举每个工作人员
i
i
i前的
[
1
,
i
−
1
]
[1,i-1]
[1,i−1]个工作人员中长度和小于等于
s
s
s的个数。
正解其实也很显然,先降序排列人的长度,再同样枚举每个工作人员
i
i
i,然后二分搜索
[
i
+
1
,
n
]
[i+1,n]
[i+1,n]中与
i
i
i之和小于等于
s
s
s的最大值
j
j
j,第
i
i
i个人的答案即为
n
−
j
+
1
n-j+1
n−j+1,最后累计求和即可。
上代码:
#include<bits/stdc++.h>
using namespace std;
#define in read()
int in
{
int i=0;char ch=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) i=i*10+ch-'0',ch=getchar();
return i;
}
int n,s,an,a[200005];
long long ans;
bool comp(const int &x,const int &y)
{
return x>y;
}
int find(int l,int r)
{
int data=a[l-1];
while(l<r)
{
int mid=l+r>>1;
if(a[mid]+data<=s) r=mid;
else l=mid+1;
}
return l;
}
int main()
{
n=in;s=in;
for(int i=1;i<=n;i++) a[i]=in;
sort(a+1,a+n+1,comp);
for(int i=1;i<=n;i++)
{
if(a[i]>=s) continue;
an=find(i+1,n);
ans+=(long long)n-an+1;
}
printf("%lld",ans);
return 0;
}
也可以用 l o w e r b o u n d lowerbound lowerbound代替二分~~,但我用的不熟就没有用~~ 。
下面是T2:
这道题的解法十分巧妙,设选出来的数为
a
1
,
a
2
,
a
3
,
.
.
.
,
a
m
a_1,a_2,a_3,...,a_m
a1,a2,a3,...,am,考虑用
b
i
=
a
i
+
i
b_i=a_i+i
bi=ai+i,则
b
b
b中全是偶数且两两互不相同,一个
b
b
b唯一对应一个
a
a
a。
所以问题转化为求从
[
1
,
n
+
m
]
[1,n+m]
[1,n+m]中选
m
m
m个偶数的方案数,剩下的就是一个基础的 组合数问题(我今天才弄懂),方案数为
C
m
(
n
+
m
)
/
2
C^{(n+m)/2}_m
Cm(n+m)/2。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=998244353;
int T,n,m,fac[1000005],inv[1000005];
ll ans;
int pwr(int x,int y)
{
int ans=1;
for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) ans=(ll)ans*x%mod;
return ans;
}
void pre(int n)
{
fac[0]=1;for(int i=1;i<=n;i++) fac[i]=(ll)fac[i-1]*i%mod;
inv[n]=pwr(fac[n],mod-2);for(int i=n-1;i>=0;i--) inv[i]=(ll)inv[i+1]*(i+1)%mod;
}
ll zh(int x,int y) {return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;}
int main()
{
freopen("temple.in","r",stdin);
freopen("temple.out","w",stdout);
scanf("%d",&T);
pre(1e6);
while(T--)
{
scanf("%d%d",&n,&m);
ans=zh((n+m)/2,m);
printf("%lld\n",ans%mod);
}
return 0;
}