总结:
1.数学功底还需要加强(细节方面多注意)
2.dp还需要继续加强(各种dp类型!!!)
A.有n个[0,1]之间的随机实数,在[0,1]上均匀分布。求这n个数中的第k大数大于y的概率。
公式题:ans= ∑n−ki=0C(n,i)∗yi∗(1−y)n−i
一开始忘记加入组合数C(n,i),没有考虑到n个数是有标号的!
B.水题,不解释
C.单调队列优化dp
n个数中取出不相连的若干个区间,区间长度不超过k。在所有方案中,求选取区间和的最大值
dp[i]:前i个数中的区间和最大值
dp[i]=max(dp[j]+sum[i]−sum[j+1],max(0,i−1−k)=<j<=i−1)
提出sum[i],令dp[j]-sum[j+1]为fun(j)可得: dp[i]=max(fun(j),max(0,i−1−k)=<j<=i−1)+sum[i]
对于dp[j]-sum[j+1]在固定长度区间的最大值可以用单调队列优化!
用队列出队和入队限制区间限制和单调条件即可
#include
#include
#include
#include
using namespace std;
const int maxn =100000+10;
int n,k,a[maxn];
int que[maxn],tail,head;
int dp[maxn],sum[maxn];
int fun(int x){
return dp[x]-sum[x+1];
}
int main(){
while(scanf("%d%d",&n,&k)!=EOF){
sum[0]=0,dp[0]=0;
for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; }
tail=0,head=-1;
que[++head]=0;
for(int i=1;i<=n;i++){
//队尾出列(下标超出区间范围)————满足条件 que[tail]>=i-1-k
while(tail<=head&&que[tail]1-k) tail++;
//求dp值————dp[i]=fun(que[tail])+f(i)
int x=que[tail];
dp[i]=fun(x)+sum[i];
if(i<=k) dp[i]=max(dp[i],sum[i]);
//队头入列(挤出下标和值都小于当前数的值————满足条件:队列中元素fun值严格递减
while(tail<=head&&fun(que[head])<=fun(i)) head--;
que[++head]=i;
}
printf("%d\n",dp[n]);
}
}
D.组合dp
1.计算n个点的有向无环图(DAG图)个数
2.计算有”所有点入度不大于k”限制的n点有向无环图个数
1.dp[i][j]:i个点中j个点出度为0的DAG图个数
如果去掉该j个点及其入边后还剩k个点出度为0
dp[i][j]= ∑i−jk=1dp[i−j][k]∗(2j−1)k∗(2j)i−j−k
初始化:dp[1][1]=1
复杂度:O(n^3)
2.dp[i][j]= ∑i−jk=1dp[i−j][k]∗dp2[i][j][k]
dp2[i][j[k]:i个点中有j个点出度为0,去掉该j个点后还有k个点出度为0,且满足条件2的DAG图个数
E.区间dp
n个处于[0,100]中的数,每次合并相邻两个数,合并结果为(a+b)%100,合并代价为a*b,求合并n-1次的最小代价
特点:将区间[i,j]中的所有数合并成一个数,合并结果不随着合并方式改变,结果为[i,j]区间中所有数的和
dp[i][j]=max{dp[i][k]+dp[k+1][j]+sum[i,k]*sum[k+1,j],i<=k<=j-1}
初始化dp[i][i]=a[i]
复杂度:O(n^3)
F.水题,不解释
G.DAG图dp
求单源”边递增”最短路径。
将DAG图中的所有边从小到大排序,如果此时的起点已经加入”可行集合”,那么加入该边后以头结点更新尾节点的dis值
H.水题,不解释
I.求树的直径+求连续区间数的lcm
给一颗无根树,试确定根后使得所有点的深度的最小公倍数最大。(根节点深度为1)
1.求树的直径L
2.求1,2,3…L的最小公倍数lcm(需要对mod取模)
方法:1.筛选出1,2…L中所有的素数
2.对于任意一个素数p,lcm中p的幂次等于[n/p]
因此ans= ∏ki=1p[logpin]i ,p1,p2…pk是1,2…n中所有的素数
复杂度:O(n)
拓展:
1.求n个数的lcm(需要对mod取模),数据范围为N
做法:
1、预处理 N−−√ 范围内的所有素数
2、对n个数进行素因子分解,如果素因子大于 N−−√ ,则lcm中最多幂次为1,;如果素因子不大于 N−−√ ,则维护每个素因子的幂次最大值
复杂度:O(n* N−−√ ),对于1000个在1e9范围内的数可做
思想:用质因子分解解决lcm问题
注意:求lcm并取模,只能通过质因子方法求解!
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const ll maxn = 1000+10;
const ll mod = 1e9+7;
ll n,a[maxn];
map ma;// 记录素数i的个数cnt
set se;//set记录存在的素数i
ll ans;
set ::iterator iter;
ll Power(ll a,ll b){
ll tmp=1;
while(b){
if(b&1){ tmp=(tmp*a)%mod;b--; }
b>>=1,a=(a*a)%mod;
}
return tmp;
}
void Factor(ll x){
for(ll i=2;i*i<=x;i++){
ll cnt=0;
if(x%i==0){
while(x%i==0){
cnt++;
x/=i;
}
}
if(cnt){
if(!se.count(i)) { se.insert(i); ma[i]=cnt; }
else ma[i]=max(ma[i],cnt);
}
}
if(x!=1){
if(!se.count(x)) { se.insert(x); ma[x]=1; }
else ma[x]=max(ma[x],1ll);
}
}
int main(){
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
while(scanf("%lld",&n)!=EOF){
ma.clear();
se.clear();
ans=1;
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++){
Factor(a[i]);
}
for(iter=se.begin();iter!=se.end();iter++){
ll x=*iter;
ans=(ans*Power(x,ma[x]))%mod;
}
printf("%lld\n",ans);
}
return 0;
}
J.二次函数极值,不解释。