一.总结
后面开始打的,很多题都不是正解,都是歪门邪道/奇淫技巧,看了官方题解才恍然大悟,这里给大家介绍一下跟正解不同的黑科技做法。
二.题解
A. 怪盗-1412
一开始再由于子序列的问题,想了想第一个例子觉得不可能只是504,所以觉得自己读错题了,只能反着从样例读题。
很明显第一个例子是 6 ,7 , 8 , 答案是 504 。
因为1412中的4和2都是单一的,所以必须会相乘并成为答案的一部分,所以我尝试用504/7/8,求出9,不难联想到9是3*3,正好是6的一半。
所以答案的式子就有了:
代码:
#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int manx=1e6+5;
const int N=2e3+5;
const int mod=1e9+7;
int main(){
ll p; cin>>p;
while(p--){
ll a,b,c; cin>>a>>b>>c;
cout<<a/2*(a-a/2)*b*c<<endl;
}
return 0;
} B.Dis2
题意讲的很清楚,但是我的脑子没那么好,没有联想到直接累加跟 i 点相连的点的度-1 .
我的做法是 i 点 距离为 2 有三种:
- 比如说 i 点的深度为
,那么只要
就肯定存在一个点距离 i 点为 2.
- 还有一种就是 i 点的儿子的儿子个数累加和.
- 最后就是 i 点的父亲结点的儿子个数-1(i点本身)。
所以我用 cnt数组维护儿子个数,ans数组维护儿子的儿子个数和,具体可以看代码。
代码:
#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int manx=1e6+5;
const int N=2e3+5;
const int mod=1e9+7;
vector<ll>g[manx];
ll cnt[manx],ans[manx],f[manx],d[manx];
ll ma;
void dfs(ll u,ll pre){
d[u]=d[pre]+1; f[u]=pre;
for(auto v: g[u]){
if(v==pre) continue;
cnt[u]++;
dfs(v,u);
ans[u]+=cnt[v];
}
}
int main(){
ll n; cin>>n;
for(int i=1;i<n;i++){
ll u,v; cin>>u>>v;
g[u].pb(v); g[v].pb(u);
}
dfs(1,0);
for(int i=1;i<=n;i++){
ll x=ans[i];
// cout<<i<<" "<<x<<" "<<ans[i]<<" "<<d[i]<<endl;
if(d[i]-2>=1) x++;
x+=max(cnt[f[i]]-1,0ll);
cout<<x<<endl;
}
return 0;
} C.序列卷积之和
黑科技之打表找规律。
不难发现是个上三角矩阵且存在规律,以第一个样例可以打出下表:
4 3 2 1
0 6 4 2
0 0 6 3
0 0 0 4
所以我们可以预处理一下后缀和,然后求出答案。
代码:
#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int manx=1e6+5;
const int N=2e3+5;
const int mod=1e9+7;
ll mps[N][N];
ll a[manx],b[manx],suf[manx];
int main(){
ll n; cin>>n; ll ans=0;
for(int i=1;i<=n;i++) cin>>a[i];
/*
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++)
mps[i][j]++,ans+=a[i]*a[j];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cout<<mps[i][j]<<" ";
cout<<endl;
}
代码实际输出:4 3 2 1
0 6 4 2
0 0 6 3
0 0 0 4
1988你期望的输出:1988
*/
for(int i=n,j=1;i>=1;i--,j++) suf[i]=suf[i+1]+a[i]*j;
ll sb=(1+n)*n/2;
for(int i=1,j=1;i<=n;i++,j++){
ans=(ans+(suf[i]%mod*j%mod*a[i]%mod)%mod)%mod;
}
cout<<ans;
return 0;
} D. 宝石装箱
类似于背包?
此类计数题着手点可以从 所有方案-不合法方案 来得到合法的方案。
考虑用 维护 前 i 个箱子至少放了 j 个不合法的宝石的方案数。
但是由于内存的关系,需要滚动数组优化,可以进行类似于背包的操作
因为第 i 个箱子 至少放了 j 个不合法宝石 是用前面一个状态(dp[j-1]) 推出
所以在枚举放不合法宝石的时候逆序枚举就可以实现内存优化
然后合法宝石的排列是 , 不合法宝石的排列是
因为是至少放了 x 个不合法宝石,所以肯定存在重复的方案,就需要进行容斥
偶数加,奇数减!
代码:
#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define mod 1e9+7
#define mo 998244353
#define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int manx=1e6+5;
const int N=8e3+5;
ll a[N],dp[N],f[N];
int main(){
ll n,x; cin>>n;
f[0]=dp[0]=1;
for(int i=1;i<=n;i++) cin>>x,a[x]++,f[i]=f[i-1]*i%mo;
for(int i=1;i<=n;i++)
for(int j=i;j>=1;j--)
dp[j]=(dp[j]+dp[j-1]*a[i])%mo;
ll ans=0;
for(int i=0;i<=n;i++){
if(i&1) ans+=mo-(dp[i]*f[n-i]%mo);
else ans+=(dp[i]*f[n-i]%mo);
ans%=mo;
}
cout<<ans;
return 0;
} 
京公网安备 11010502036488号