A
知识点:贪心、乘法原理
思路:如果是给定的字符串,那么dp求解即可。但这道题只给了1、2、4的数量。显然111...1144...44111...11222...22这样是最优的,且两个1的连续子串长度之差尽可能小。
最终输出 即可。
#include<bits/stdc++.h>; using namespace std; #define ll long long const int mod = 1e9+7; int main(){ ll t; cin>>t; while(t--){ ll n,m,k; cin>>n>>m>>k; ll a=n/2,b=n-a; cout<<a*b*m*k<<endl; } }
B
知识点:图论
思路:统计所有点的度数,那么每个点距离为 的数量为它的邻点的度数之和减去邻点的个数。
#include<bits/stdc++.h>; using namespace std; #define ll long long const int mod = 1e9+7; int dp[222222]; vector<int>g[222222]; int main(){ ll n,i,j,k; cin>>n; for(i=1;i<n;i++){ ll x,y; cin>>x>>y; g[x].push_back(y); g[y].push_back(x); dp[x]++; dp[y]++; } for(i=1;i<=n;i++){ ll sum=0; for(j=0;j<g[i].size();j++){ sum+=dp[g[i][j]]-1; } cout<<sum<<endl; } }
C
知识点:dp
思路:这道题其实就是求所有子区间的区间内部两两乘积之和。
我们先把问题分解,假设 为前 个数的最终答案,那么 比 多了哪些区间呢?答案是这些。
那么我们可以先转换一下思路,设 为 这些区间内部的两两乘积之和,这些区间里的乘积可以分为两类,含 的和不含 的。
含的部分,有 个 , 个 , ... 个。这些部分可以前缀和预处理搞定。
不含 的部分,可以看成为 这些区间内部的两两乘积之和,正好是dp2[i-1]。
那么这道题就做出来了。
(当时推的时候思路没这么清晰,把 单独拿出来了,繁琐了很多)。
#include<bits/stdc++.h>; using namespace std; #define ll long long const int mod = 1e9+7; ll dp[200202],dp2[200020],sum[200020],dpp[200020]; ll a[200202]; ll power(ll a,ll b){ ll res=1; while(b){ if(b&1)res=res*a%mod; b>>=1; a=a*a%mod; } return res; } int main(){ ll n,i,j,k; cin>>n; for(i=1;i<=n;i++){ cin>>a[i]; sum[i]=sum[i-1]+a[i]; dp2[i]=dp2[i-1]+sum[i]; sum[i]%=mod; dp2[i]%=mod; } dpp[1]=a[1]*a[1]; for(i=2;i<=n;i++){ dpp[i]=dpp[i-1]+(sum[i-1]*i%mod-dp2[i-1]+mod)*a[i]%mod+(i)*a[i]%mod*a[i]%mod; dpp[i]%=mod; } //for(i=1;i<=n;i++)cout<<sum[i]<<" "<<dpp[i]<<endl; for(i=1;i<=n;i++) dp[1]=a[1]*a[1]; for(i=2;i<=n;i++){ // cout<<(sum[i-1]*i%mod-dp2[i-1]+mod)%mod<<endl; dp[i]=dp[i-1]+a[i]*a[i]%mod*i%mod+(sum[i-1]*i%mod-dp2[i-1]+mod)*a[i]%mod+dpp[i-1]; dp[i]%=mod; } cout<<dp[n]; }
D
知识点:dp、容斥原理
思路:这道题直接正向求不太好求,可以反向思维:一共有 个排列,把所有不合法的情况减去,就是合法的情况。
不合法的情况可以这样去求:
先用一个桶来统计每个位置的不合法的宝石数量( 可以跳过不统计),记为 。
首先有1个位置不合法的总方案共有
2个位置不合法的总方案共有
3个位置不合法的总方案共有
问题就是如何求里面的和式了。这个可以用二维dp解决,设 为前 个数里,取 个数乘积之和,那么有:
求完了这些之后,我们可以用 减去1个位置不合法的方案数,那么2个位置不合法的情况被多减了一次,需要加回来,3个位置不合法的情况又被加多了,再减掉。。以此类推,最终求出来的就是合法方案的总数。
注意这道题 范围是8000, 的时间复杂度可以过,但空间复杂度不行,所以只能开滚动数组进行dp(我就是第一发开的二维数组导致mle一次QAQ)
#include<bits/stdc++.h>; using namespace std; #define ll long long const int mod = 998244353; ll jc[200020]; ll power(ll a,ll b){ ll res=1; while(b){ if(b&1)res=res*a%mod; b>>=1; a=a*a%mod; } return res; } ll inv(ll x){ power(x,mod-2); } ll a[20002],t[20002],b[20002],dp[3][8002]; int main(){ ll n,i,j=1,k; cin>>n; ll tt=1; jc[0]=1; for(i=1;i<=n;i++)jc[i]=tt=tt*i%mod; for(i=0;i<n;i++)cin>>a[i],t[a[i]]++; int jud=-1,temp=n; for(i=1;i<=n;i++){ if(t[i])b[j++]=t[i]; } j--; //for(i=1;i<=j;i++)cout<<dp[i][j]<<endl; ll res=jc[n]; for(i=1;i<=j;i++){ if(i==1){ for(k=1;k<=j;k++){ dp[1][k]=(dp[1][k-1]+b[k])%mod; } } else{ for(k=1;k<=j;k++){ dp[0][k]=dp[1][k]; } for(k=1;k<=j;k++){ dp[1][k]=(dp[1][k-1]+dp[0][k-1]*b[k])%mod; } } res+=jud*jc[n-i]*dp[1][j]%mod,jud*=-1; res=(res+mod)%mod; // cout<<res<<endl; } cout<<res; }