DP cf题

D. Weight the Tree

给一棵树,每个点有权重,如果一个点的权重等于它周围直接相连点的权重,就称为好点,求权重的分配方案,使得好点个数最大化,且权重值之和最小,

做法:设\(dp[x][1/0]\)表示当前点是否作为好点时最大好点数,最小权值,我们可以知道,如果一个点为好点,他周围的点就不会是好点,权重就是1,那么他的权重最小就为度数 ,所以$$dp[x][1]= \sum_{v,son[x]} dp[v][0], dp[x][0] = \sum_{v,son[x]} min(dp[v][0],dp[v][1]) $$

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int maxn=2e5+10;

class node{
    public:
    int x,y;

    node(int _x=0,int _y=0){
        x=_x;
        y=_y;
    }

    node operator + (const node &rhs){
        node ans;
        ans.x=x+rhs.x;
        ans.y=y+rhs.y;
        return ans;
    }

    bool operator < (const node &rhs){
        if(x==rhs.x) return y<rhs.y;
        else return x>rhs.x;
    }
};

vector<int>G[maxn];
node dp[maxn][2];
int du[maxn];
int ans[maxn];

void dfs1(int x,int f){
    for (auto v:G[x]){
        if(v==f) continue;
        dfs1(v,x);
        dp[x][1]=dp[x][1]+dp[v][0];
        if(dp[v][0]<dp[v][1]){
            dp[x][0]=dp[x][0]+dp[v][0];
        }else dp[x][0]=dp[x][0]+dp[v][1];
    }
    dp[x][1]=dp[x][1]+node(1,du[x]);
    dp[x][0]=dp[x][0]+node(0,1);
}

void dfs2(int x,int f,int num){
    if(num==0) ans[x]=1;
    else ans[x]=du[x];
    for (auto v:G[x]){
        if(v==f) continue;
        if(num==1){
            dfs2(v,x,0);
        }else {
           if(dp[v][0]<dp[v][1]){
               dfs2(v,x,0);
           }else dfs2(v,x,1); 
        }
    }
}

int main(){
    int n;
    scanf("%d",&n);
    for (int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
        du[v]++;
        du[u]++;
    } 
    if(n==2){
        printf("2 2\n1 1\n");
        return 0;
    }

    dfs1(1,1);
    if(dp[1][0]<dp[1][1]) cout<<dp[1][0].x<<" "<<dp[1][0].y,dfs2(1,1,0);
    else cout<<dp[1][1].x<<" "<<dp[1][1].y,dfs2(1,1,1);
    puts("");
    for (int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}

Codeforces Round #772 (Div. 2)

D. Infinite Set

题意:给出n个不同数\(a_i\)和p (集合S中所有元素均小于2^p),维护集合S S,该集合里的元素x满足:

\(n,p<=10^5\) ,$ a_i<=10^9 $

  1. \(a_i\)都在集合里

  2. \(y=2*x+1\) ,x在集合S中

  3. \(y=4*x\)

做法:因为2^p很大,所以考虑到可以按位来做,设dp[i],表示\(2^i<=x<=2^{i+1}\)情况下答案为多少,那么对于\(y=2*x+1\)\(y=4*x\),就等价于dp[i]=dp[i-1]+dp[i-2],对于每个数,统计其对应dp[i]的答案即可,在统计的时候为了避免答案重复,需要把a[i]中能够互相表出的数删掉,留下不能由其它数表出的数,但这道题卡场,不要直接用map查和做,常数很大,用set记录是否有解就好

点击查看代码
#include<bits/stdc++.h>
using namespace std;

#define Max(a,b) (a)>(b)?(a):(b)
typedef long long ll;
const int maxn=2e5+10;
const ll mod=1e9+7;

ll dp[maxn];
map<int,bool>mp;

int main(){
    int n,p;
    scanf("%d%d",&n,&p);
    for (int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        if(mp.find(x)==mp.end())
            mp[x]=1;
    }
    ll ans=0;
    set<int>s;
    for (auto it=mp.begin();it!=mp.end();it++){
        int x=it->first;
        bool flag=1;
        while(x>0){
            if(s.find(x)!=s.end()) {flag=0;}
            if(x&1){
                x>>=1;
            }else if(x%4) break;
            else{
                x>>=2;
            }
        } 
        if(flag)
        s.insert(it->first);
    }
    auto it=s.begin();
    int num=0,sum=1;
    for (;it!=s.end();it++){
      //  cout<<*it<<endl;
           int x=*it;
           while(x>=sum*2){
               sum*=2;
               num++;
           }
           dp[num]++;
    }
    dp[1]+=dp[0];
    for (int j=2;j<p;j++){
        //printf("%lld ",dp[j]);
        dp[j]=(dp[j-1]+dp[j-2]+dp[j])%mod;
    }
    for (int j=0;j<p;j++){
        ans=(ans+dp[j])%mod;
    }
    printf("%lld\n",ans%mod);
    return 0;
}

Bayan 2015 Contest Warm UpD. CGCDSSQ

做法,固定右端点,去更新做端点以获得区间,我们知道区间gcd最多只有Log(maxnum)个不同的值,所以处理复杂度其实就是nlognlogc,因为再套上了一个map

点击查看代码
#include <bits/stdc++.h>
using namespace std;

int a[100010];

typedef long long ll;

int gcd(int x,int y){
    if(y==0) return x;
    return gcd(y,x%y);
}

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    vector< pair<int,int> >g[2];
    map<int,ll>ans;
    int l1=0,l2=0;
    for (int i=1;i<=n;i++){
        l1=l2;
        l2=l1^1;
        g[l2].clear();
        g[l2].push_back(make_pair(i,a[i]));
        int last=a[i];
        for (auto x:g[l1]){
            int p=gcd(x.second,a[i]);
            if(p==last){
                g[l2][g[l2].size()-1]=make_pair(x.first,p);
            }else {
                g[l2].push_back(make_pair(x.first,p));
                last=p;
            }
        }

        last=i;
        for (auto x:g[l2]){
            int now=x.first;
           // cout<<x.second<<" "<<x.first<<" ";
            ans[x.second]+=(ll)(last-now+1);
            last=now-1;
        }
        //cout<<endl;
    }

    int q;
    cin>>q;
    while(q--){
        int x;
        cin>>x;
        cout<<ans[x]<<endl;
    }
    return 0;
}

Codeforces Round #766 (Div. 2) D. Not Adding

考虑到几个数的gcd不会大于这几个数中的任意一个,我们就从1-max扫一遍,看这些数哪个可以被表出来,而且每个数都是x的倍数,那么就类似做埃式筛法,最后复杂度是\(O(n)+alog(a)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int maxn=1e6+10;

int vis[maxn];

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif

    int n,maxx=0,x;
    cin>>n;
    for (int i=1;i<=n;i++){
        scanf("%d",&x);
        vis[x]++;
        maxx=max(maxx,x);
    }
    int ans=0;
    for (int i=1;i<=maxx;i++){
        int pre=0;
        if(vis[i]) continue;
        for (int j=i;j<=maxn;j+=i){
            if(!vis[j]) continue;
            pre=__gcd(pre,j);
            if(pre==i){
                ans++;
                break;
            }
        }
    }

    cout<<ans<<endl;
    return 0;
}

Codeforces Round #764 (Div. 3) E. Masha-forgetful

考虑到长度大于3的每个串可以由长度为2和3构成,那么我们就直接把每个串拆成长度2和3的小串,然后dp就好,设\(dp[i][0/1]\)表示到第i个数采用长度为,\(2/3\)的串,转移就好

点击查看代码
#include <bits/stdc++.h>
using namespace std;

const int maxn=1010;

class my{
    public:
        int l,r,id;
        my(int _l=0,int _r=0,int _id=0){
            l=_l,r=_r,id=_id;
        }

        bool operator<(const my &rhs)const{
            return id<rhs.id;
        }
};

map<string,my>mp;
int dp[maxn][2];

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif

    int T;
    scanf("%d",&T);
    while(T--){
        mp.clear();
        int n,m;
        getchar();
        getchar();
        cin>>n>>m;
        string s;
        for (int i=0;i<=m;i++) dp[i][0]=dp[i][1]=0;
        for (int k=1;k<=n;k++){
            cin>>s;
            for(int i=0;i<m;i++){
                string p1="",p2="";
                if(i+1<m){
                    for (int o=i;o<=i+1;o++)
                        p1+=s[o];
                    my x(i+1,i+2,k);
                    if(mp.find(p1)==mp.end()) mp.insert(pair<string, my>(p1, x));
                }
                if(i+2<m){
                    for (int o=i;o<=i+2;o++)
                        p2+=s[o];
                    my x(i+1,i+3,k);
                    if(mp.find(p2)==mp.end()) mp.insert(pair<string, my>(p2, x));
                }
            }
        }
        char S[1010];
        S[0]='0';
        scanf("%s",S+1);
        s=S;
        dp[0][0]=1;
        dp[0][1]=1;
        for (int i=2;i<=m;i++){
            for (int j=0;j<2;j++){
                if(i>=2 && dp[i-2][j]){
                    string p="";
                    for (int o=i-1;o<=i;o++)
                        p+=s[o];
                    if(mp.find(p)!=mp.end()) dp[i][0]=1;
                }
                if(i>=3 && dp[i-3][j]){
                    string p="";
                     for (int o=i-2;o<=i;o++)
                        p+=s[o];
                    if(mp.find(p)!=mp.end()) dp[i][1]=1;
                }
            }
        }
        if(!dp[m][1] && !dp[m][0]){puts("-1");continue;}
        vector<my>ans;
        int pre=m;
        while(pre>=2){
            if(dp[pre][0]){
                string p="";
                for (int o=pre-1;o<=pre;o++)
                    p+=s[o];
                ans.push_back(mp[p]);pre-=2;
            }else {
                string p="";
                for (int o=pre-2;o<=pre;o++)
                    p+=s[o];
                ans.push_back(mp[p]);pre-=3;
            }
        }
        reverse(ans.begin(),ans.end());
        cout<<ans.size()<<endl;
        for (auto x:ans){
            printf("%d %d %d\n",x.l,x.r,x.id);
        }
    }
    return 0;
}
posted @ 2022-03-21 21:53  lmj_1  阅读(75)  评论(0)    收藏  举报