cf自训4.10

cf933A dp题

一开始看错是连续子序列了,然后样例刚好能过。。

然后正解没想出来,网上看了题解:感觉正解是枚举2开始的位置,然后再枚举翻转的区间,pos左右两侧分别求出贡献最大的那个区间,左右两部分的贡献是独立计算的

#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
 
typedef long long ll;
const int maxn = 2005;
const ll mod = 1e9+7;
const ll INF = 1e18+5;
const double eps = 1e-9;
 
int n;
int a[maxn];
int pre1[maxn];
int pre2[maxn];
 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pre1[i]=pre1[i-1]+(a[i]==1);
    }
    for(int i=n;i>=1;i--) pre2[i]=pre2[i+1]+(a[i]==2);
    int ans=0;
    for(int k=1;k<=n+1;k++)                   //枚举位置pos
    {
        int num1=0,num2=0;
        for(int i=1;i<=k;i++) num1=max(num1,pre1[i-1]+pre2[i]-pre2[k]);   //枚举l
        for(int i=k;i<=n+1;i++) num2=max(num2,pre2[i]+pre1[i-1]-pre1[k-1]);  //枚举r
        ans=max(ans,num1+num2);
    }
    printf("%d\n",ans);
}
View Code

然后是神仙做法,因为答案必定是11111222221111122222的前缀样式,所以只要从左到右扫一次即可。。

#include<bits/stdc++.h>
using namespace std;

#define maxn 2000

int n;
int a[maxn+5];
int f[maxn+5][5];

int main() {
    scanf("%d",&n);
    for(int i=1; i<=n; i++) scanf("%d",&a[i]);
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=4; j++) {
            f[i][j]=f[i][j-1];
            if(a[i]==(j+1)%2+1) f[i][j]=max(f[i][j],f[i-1][j]+1);
            else f[i][j]=max(f[i][j],f[i-1][j]);
        }
    }
    printf("%d",f[n][4]);
    return 0;
}
View Code

cf938D 最短路+新建源点

第一次在cf上做这种题,这题就是把每个点权转化为到源点的边权,然后跑一次最短路即可

/*
给定无向图,有边权和点权
现在要求出每个点i的最小代价2*d(i,j)+aj,i可以等于j 
建图:边权*2,建立源点和每个点连边,边权是ai
然后以源点为起点跑最短路即可 
*/
#include<bits/stdc++.h>
#include<queue>
using namespace std;
#define maxn 400005
#define ll long long
struct Edge{ll to,nxt,w;}edge[maxn<<2]; 
ll head[maxn],tot,n,m,a[maxn];
void init(){
    memset(head,-1,sizeof head);
    tot=0;
}
void addedge(ll u,ll v,ll w){
    edge[tot].to=v;edge[tot].w=w;
    edge[tot].nxt=head[u];head[u]=tot++;
}

ll d[maxn],v[maxn];
priority_queue<pair<ll,ll> >pq;
void dijkstra(){
    memset(d,0x3f,sizeof d);
    memset(v,0,sizeof v);
    d[n+1]=0;
    pq.push(make_pair(0,n+1));
    while(pq.size()){
        pair<ll,ll>c=pq.top();pq.pop();
        if(v[c.second])continue;
        v[c.second]=1;
        ll x=c.second;
        for(int i=head[x];i!=-1;i=edge[i].nxt){
            ll y=edge[i].to,w=edge[i].w;
            if(v[y])continue;
            if(d[y]>d[x]+w){
                d[y]=d[x]+w;
                pq.push(make_pair(-d[y],y));
            }
        }
    }
}


int main(){
    init();
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        ll u,v,w;
        cin>>u>>v>>w;
        addedge(u,v,2*w);
        addedge(v,u,2*w); 
    }
    for(int i=1;i<=n;i++){
        cin>>a[i];
        addedge(i,n+1,a[i]);
        addedge(n+1,i,a[i]);
    }
    dijkstra();
    
    for(int i=1;i<=n;i++)
        cout<<d[i]<<" ";    
} 
View Code

cf939E 三分+简单公式

学了下三分的写法,能用来求单峰函数的极值

三分链接: https://blog.csdn.net/pi9nc/article/details/9666627 

/*
1.往多重集合s里加数 ,每次给的数时单调不递减的 
2.求子集ss,使max(ss)-mean(ss)最大 
三分法来做即可 
*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
#define ll long long
double sum[maxn],n;
ll len,Max;
double f(int i){
    return ((double)sum[i]+Max)/(i+1);
}
double sanfen(int l,int r){
    while(l<r-1){
        int mid=(l+r)>>1;
        int mmid=(mid+r)>>1;
        if(f(mid)>f(mmid))
            l=mid;
        else r=mmid;
    }
    if(f(l)>f(r))return f(r);
    return f(l);
}
int main(){
    int q,op;
    cin>>q;
    while(q--){
        cin>>op;
        if(op==1){
            cin>>Max;
            sum[++len]=Max+sum[len-1];        
        }
        else {
            printf("%.10lf\n",Max-sanfen(1,len-1));
        }
    }    
} 
View Code

cf935D 概率递推dp

还是第一次做这种题。。要学一下概率dp了。。

/*
概率递推+逆元取模运算
从末尾往前推比从前往后推要更简单 
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define mod 1000000007
#define maxn 100005
ll a[maxn],b[maxn],n,m,dp[maxn];
ll inv2,invm;
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){x=1,y=0;return a;}
    ll d=exgcd(b,a%b,x,y);
    ll z=x;x=y;y=z-a/b*x;
    return d;
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)cin>>b[i];
    ll x,y;
    exgcd(2,mod,x,y);inv2=(x+mod)%mod;
    exgcd(m,mod,x,y);invm=(x+mod)%mod;
    for(int i=n;i>=1;i--){
        if(a[i] && b[i]){//第i位都是固定的数 
            if(a[i]==b[i])dp[i]=dp[i+1];
            else dp[i]=a[i]>b[i];
        }
        else if(b[i])//ai填数,ai==bi的概率+ai>bi的概率 
            dp[i]=dp[i+1]*invm%mod+(m-b[i])*invm%mod; 
        else if(a[i])//bi填数,ai==bi的概率+ai>bi的概率 
            dp[i]=dp[i+1]*invm%mod+(a[i]-1)*invm%mod; 
        else if(!a[i] && !b[i])//都填数,ai==bi的概率+ai!=bi且ai>bi的概率 
            dp[i]=dp[i+1]*invm%mod+(m-1)*inv2%mod*invm%mod;
    }
    cout<<dp[1]%mod<<endl;
} 
View Code

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/10686768.html