A
Description
给定 与 ,输出 。
Solution
直接模拟即可。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a,b;
signed main()
{
cin>>a>>b;
cout<<a*b<<endl;
return 0;
}
B
Description
给定 个数,请求出它们的乘积。特别的,如果该值大于 则输出 。
Solution
显然,由题意可以写出这个式子:
if (tot*a[i]>1000000000000000000) return cout<<-1<<endl,0;
注意,这里的 会溢出!既然乘法不行,就用除法呗~
if (tot>1000000000000000000/a[i]) return cout<<-1<<endl,0;
注意,这两个式子可以互相转换的,依据是不等式的基本性质。
还有一件重要的事情——在判断溢出前,看一下给定的那些数中是否有 ,如果有就直接输出 并结束程序。
Code
#include <bits/stdc++.h>
#define int long long
#define inf 1000000000000000000
using namespace std;
int n,tot=1,a[200005];
signed main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++)
{
if (a[i]==0) return cout<<0<<endl,0;
}
for (int i=1;i<=n;i++)
{
if (tot>inf/a[i]) return cout<<-1<<endl,0;
tot*=a[i];
}
cout<<tot<<endl;
return 0;
}
C
不会做……
D
Description
尽可能多地把 拆分为多个不同的,且是某个质数的正整数次方数 的数的乘积,并输出最多的个数。
Solution
做法显然。先质因数分解,即 。
可以得到,对于每对 ,我们需要将 拆分为 ,并且要拆分得尽可能地多;所以,假设最多可以拆分为 个,那么答案就是 。
注意质因数分解的时间复杂度需要限制在 以内,如果不会可以看我的另外一篇博客——质因数分解详解。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,ans=0;
signed main()
{
cin>>n;
if (n==1) return cout<<0<<endl,0;
for (int i=2;i*i<=n;i++)
{
if (n%i==0)
{
int pos=0;
while (n%i==0) n=n/i,pos++;
int now=sqrt(pos*2);
if (now*(now+1)>pos*2) now--;
ans+=now;
}
}
if (n>1) ans++;
cout<<ans<<endl;
return 0;
}
E
Description
给定 对 与 ,且数组 满足 。现在,请求出数组 有多少种不同的中位数。
solution
显然,我们要分奇偶类讨论。
①
为奇数。
容易发现,此时中位数仅仅与
数组中最中间的那个数
有关。于是,我们将
数组与
数组按升序排序,那么有
。所以,此时中位数有
种。
②
为偶数。
容易发现,此时中位数与
数组中最中间的那两个数
有关;只要
的值不同,那么中位数就不同(中位数为
)。于是,我们将
数组与
数组按升序排序,那么有
,其中
。所以,此时中位数有
种。
时间复杂度: 。
显然不可能做到这么优秀。
排序时间复杂度:
总时间复杂度:
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,ans;
int a[200005],b[200005];
signed main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i]>>b[i];
sort(a+1,a+n+1);
sort(b+1,b+n+1);
if (n%2==0) ans=b[n/2]+b[(n/2)+1]-a[n/2]-a[(n/2)+1]+1;
else ans=b[(n+1)/2]-a[(n+1)/2]+1;
cout<<ans<<endl;
return 0;
}
F
Description
给定集合 (暂且当 中数可以重复),请问存在多少个不同的 的子集使得子集中存在子集的和为 ?
由于答案可能过大,请将其对 取模。
Solution
显然,如果集合 的某个大小为 的子集 满足要求,那么它对答案的贡献就是 。
然后设计状态,其中 表示所有数和为 的子集对答案的贡献之和。
接着,考虑状态转移。如果某个和为 的子集大小为 ,添加了一个数 后成为了一个和为 且大小为 的子集,贡献也除以了2(贡献从 变成了 )。
所以,状态转移就是: 。
但是,状态转移涉及到除法与取模,所以除以2要用逆元。
时间复杂度: 。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int n,s;
int a[3005],dp[3005];
int quick_power(int x,int y)
{
int res=1;
for (;y;y=y>>1,x=(x*x)%mod)
{
if (y&1) res=(res*x)%mod;
}
return res;
}
signed main()
{
cin>>n>>s;
for (int i=1;i<=n;i++) cin>>a[i];
dp[0]=quick_power(2,n);
for (int i=1;i<=n;i++)
{
for (int j=s;j>=a[i];j--) dp[j]=(dp[j]+(dp[j-a[i]]*499122177)%mod)%mod;
}
cout<<dp[s]<<endl;
return 0;
}
总结
排名没进前3500,太惨了,赛后诸葛亮……
①A题切掉;
②B题WA了10次才AC,罚时50分钟;甚至有几次提交了同样的WA代码;心态崩溃;
④D题切掉;
⑤E题看都没看,直接搞B题去了……比赛后看到E题才发现如此简单;
⑥F题快速幂板子打错,且忘记逆元,不知道在搞啥QWQ
最终死得非常惨,大家不要学我这个菜鸡啊~
我艹%&#&@*