比赛链接:https://ac.nowcoder.com/acm/contest/5633
A:https://ac.nowcoder.com/acm/contest/5633/A
题意:给你n,m,k个1,2,4。要你对这些数字进行排序,使得排序后的这串数字中有mx个“1412”子串,求mx的最大值。
思路:不难想,这串数字必定会是形如111( 个)……444……111(
个)……222这样的(n1+n2=n),也就是2一定在最后,4一定夹在两组1之间,1被分为两组,那么此时的子串数就是n1 * k * n2 * m。要想这个值最大,也就变成,在n一定的情况下,求n1*n2的最大值,很容易知道这个最大值是
*(
+(n&1))。至此代码也就写出来了
//author CN.TTDragon
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
const ll maxn=1e5+7;
const double pi=acos(-1);
using namespace std;
int main()
{
ios::sync_with_stdio(false);
ll t;
cin>>t;//t组数据
while(t--)
{
ll n,m,k;
cin>>n>>m>>k;
if(n<2||m<1||k<1)//那种数量本身就不够的,特判一下
{
cout<<0<<endl;
continue;
}
if(n&1)//n为奇数
{
cout<<(n/2)*((n/2)+1)*m*k<<endl;
continue;
}
else//n为偶数
{
cout<<(n/2)*(n/2)*m*k<<endl;
}
}
return 0;
}
B:https://ac.nowcoder.com/acm/contest/5633/B
题意:给你一颗树,问你对于每个点有多少个点和它的距离是2。
思路:对于每个点,如果它连接了不止一个点,那么这些点之间的距离就是2。很容易想到它们是不会重复的。至此代码也就可以写出来了。
//author CN.TTDragon
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
const ll maxn=2e5+7;
const double pi=acos(-1);
using namespace std;
vector<int > e[maxn];
ll ans[maxn]={0};
int main()
{
//ios::sync_with_stdio(false);
ll n;
cin>>n;
ll a,b;
for(int i=0;i<n-1;i++)
{
cin>>a>>b;
e[a].push_back(b);
e[b].push_back(a);
}
for(int i=1;i<=n;i++)
{
if(e[i].size()>1)//如果这个点连接的点数大于1
{
for(size_t j=0;j<e[i].size();j++)
{
ans[e[i][j]]+=e[i].size()-1;//记得减去自己
}
}
}
for(int i=1;i<=n;i++)
{
cout<<ans[i]<<endl;
}
return 0;
}C:https://ac.nowcoder.com/acm/contest/5633/C
题意:给你一个数组,要你计算 。
思路:一上来肯定不明白这个这个式子的意义,但你明白它是两个数相乘然后求和,那么我们打个表来看看每对数字都乘几次
ll b[maxn][maxn];//代表ai和aj乘了几次。
for(int l=1;l<=n;l++)
{
for(int r=l;r<=n;r++)
{
for(int i=l;i<=r;i++)
{
for(int j=i;j<=r;j++)
{
b[i][j]++;
}
}
}
}看一下样例:
这一下子,我们就从O(n^4)优化到O(n^2),当然依旧不够。
还需要再次降低。
我们可以先把O(n^2)的核心部分写出来。
至于(n-j+1)这个系数怎么来的,你可以看看上面的图,超级直观有没有!
for (int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
ans+=i*a[i]*a[j]*(n-j+1);//这里是优化点
ans%=mod;
}
}仔细观察,我们会发现其实我们要的是 ,那么很容易就发现
每次都要从i到n,那么这里就可以用前缀和来降低一下复杂度。至此代码也就写出来了,但是要注意,因为它不停的在取模,很可能后面的前缀和比前面的前缀和小,但是后面肯定比前面大啊!所以在求两个前缀和的差的时候要补上一个mod来避免取负数模,使得差值一定是正数。
//author CN.TTDragon
#include<bits/stdc++.h>
typedef long long ll;
const ll mod=1e9+7;
const ll maxn=2e5+7;
const double pi=acos(-1);
using namespace std;
ll a[maxn]={0};
ll sum[maxn]={0};
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
ll ans=0;
sum[0]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
sum[i]=(sum[i-1]+(a[i]*(n-i+1)%mod))%mod;//维护前缀和。
}
for(int i = 1; i <= n; i++)
{
ans+=(((i*a[i])%mod)*((sum[n]-sum[i-1]+mod)%mod))%mod;//记得加一个mod。
ans%=mod;
}
cout<<ans<<endl;
return 0;
}写在最后:
C题一步一步的把复杂度从O(n^4)降到O(n)超级有成就感,感谢@Kur1su大佬的帮助!大佬的B题写的也超级棒,让不会树学的我也能写出来了。

京公网安备 11010502036488号