辽宁省赛总结

来源:互联网 发布:2016淘宝销售排行榜 编辑:程序博客网 时间:2024/05/01 09:56

总结:
1.数学功底还需要加强(细节方面多注意)
2.dp还需要继续加强(各种dp类型!!!)
A.有n个[0,1]之间的随机实数,在[0,1]上均匀分布。求这n个数中的第k大数大于y的概率。
公式题:ans=nki=0C(n,i)yi(1y)ni
一开始忘记加入组合数C(n,i),没有考虑到n个数是有标号的!
B.水题,不解释
C.单调队列优化dp
n个数中取出不相连的若干个区间,区间长度不超过k。在所有方案中,求选取区间和的最大值
dp[i]:前i个数中的区间和最大值
dp[i]=max(dp[j]+sum[i]sum[j+1],max(0,i1k)=<j<=i1)
提出sum[i],令dp[j]-sum[j+1]为fun(j)可得:dp[i]=max(fun(j),max(0,i1k)=<j<=i1)+sum[i]
对于dp[j]-sum[j+1]在固定长度区间的最大值可以用单调队列优化!
用队列出队和入队限制区间限制和单调条件即可

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>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]<i-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]=ijk=1dp[ij][k](2j1)k(2j)ijk
初始化:dp[1][1]=1
复杂度:O(n^3)
2.dp[i][j]=ijk=1dp[ij][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<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<set>#include<vector>#include<map>#define ll long longusing namespace std;const ll maxn = 1000+10;const ll mod = 1e9+7;ll n,a[maxn];map<ll,ll> ma;//<i,cnt> 记录素数i的个数cntset<ll> se;//set<i>记录存在的素数ill ans;set<ll>::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.二次函数极值,不解释。

0 0
原创粉丝点击