Codeforces Round 264 (Div. 2)


layout: post
title: Codeforces Round 264 (Div. 2)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces
- DP


传送门

A - Caisa and Sugar (签到)

B - Caisa and Pylons (根据能量守恒定理hhh)

C - Gargari and Bishops (模拟)

题意

给出一个棋盘你可以放两个皇后,皇后可以攻击和他一个对角线的对象。但是两个皇后不能攻击到同一个目标 求出皇后攻击目标后获得的最大值

思路

首先对于对角线正对角线的x+y都是固定的,反对角线的X-Y都是固定的

然后我们就枚举对角线的值就行,

通过观察发现不相交的对角线他们的x+y的奇偶不同。所以我们分别求出最大即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e3+50;

ll a[maxn][maxn];
ll maxL[maxn*2];
ll maxR[maxn*2];
int main(){

    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&a[i][j]);
            maxL[i+j]+=a[i][j];
            maxR[i-j+n]+=a[i][j];
        }
    }
    ll even=0,odd=0,sx,sy,ex,ey;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if((i+j)&1){
                if(maxL[i+j]+maxR[i-j+n]-a[i][j]>=odd){
                    odd=maxL[i+j]+maxR[i-j+n]-a[i][j];
                    sx=i;sy=j;
                }
            }
            else{
                if(maxL[i+j]+maxR[i-j+n]-a[i][j]>=even){
                    even=maxL[i+j]+maxR[i-j+n]-a[i][j];
                    ex=i;ey=j;
                }
            }
        }
    }
    printf("%lld\n",even+odd);
    printf("%lld %lld %lld %lld\n",sx,sy,ex,ey);
    return 0;
}

D - Gargari and Permutations (DP)

题意

求出K个排列的LCS

思路

两种解法:

DP:首先对于第一个排列他们之间的大小关系肯定是固定的,所以我们可以枚举第一个排列的大小关系,判断这个关系在其他k-1个排列中是否也符合 如果符合那么后者的答案就可以从前者身上转移而来 \(dp[i]=max(dp[i],dp[j]+1)\)

dfs: 前半部分相同,后面改成每一个符合的关系一起建图。对于每个点求出一个最长路。

//dp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e3+50;
int a[6][maxn];
int id[6][maxn];
int dp[maxn];
int now[maxn];
int k;
bool ok(int u,int v){
    for(int i=2;i<=k;i++){
        if(id[i][u]<id[i][v])return false;
    }
    return true;
}
int main(){
    int n;
    cin>>n>>k;
    for(int j=1;j<=k;j++)
        for(int i=1;i<=n;i++){
            cin>>a[j][i];
            id[j][a[j][i]]=i;
        }
    for(int i=1;i<=n;i++){
        dp[i]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<i;j++){
            if(ok(a[1][i],a[1][j]))dp[a[1][i]]=max(dp[a[1][i]],dp[a[1][j]]+1);
        }
    }
    cout<<*max_element(dp+1,dp+n+1)<<endl;
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e3+50;
#define bug cout<<"hello"<<endl;
int a[6][maxn];
int id[6][maxn];
int dp[maxn];
int now[maxn];
int k;
bool ok(int u,int v){
    for(int i=1;i<=k;i++){
        if(id[i][u]>id[i][v])return false;
    }
    return true;
}
vector<int>ve[maxn];
int dfs(int u){
    if(dp[u]!=-1)return dp[u];
    int mx=0;
    for(int i=0;i<ve[u].size();i++){
        mx=max(mx,dfs(ve[u][i]));
    }
    return dp[u]=mx+1;
}
int main(){
    int n;
    cin>>n>>k;
    memset(dp,-1,sizeof(dp));
    for(int j=1;j<=k;j++)
        for(int i=1;i<=n;i++){
            cin>>a[j][i];
            id[j][a[j][i]]=i;
        }

    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if((i!=j)&&ok(i,j)){
                ve[i].push_back(j);
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,dfs(i));
    }
    cout<<ans<<endl;
    return 0;

E - Caisa and Tree (暴力/素数筛选)

题意

给你一个树,让你求根(1)到一个点(v)之间路径上和v的值之间GCD不为1的且深度最大的点编号 有五十次修改一个点的操作

思路

看到50次修改就已经想到了暴力了。

但是还是想用正常操作做。

初始化每个值的素因子

首先我们对于每个点存一个他的素因子,然后在每次修改的时候重新建图。从根结点开始开一个栈,让遍历到的点进去,判断这个点的素因子是否出现在刚才遍历的路径中。然后选一个最大的。后把当前这个点也入栈。遍历这个点的儿子们。然后回溯的时候把所有的素因子中包括他的弹开。

//讲道理每个素因子开一个vector就可以了。可是一直过不去,其他人用map就过去了。。

第二种暴力解法。对于每个操作离线存起来,然后在修改的时候再把之间的询问一次性遍历。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+50;
#define bug cout<<"hello"<<endl;
int n,q;
int a[maxn];
int prime[maxn];
bool check[maxn];
int cnt;

void init(int N){
    for(int i=2;i<=N;i++){
        if(!check[i]){
            prime[++cnt]=i;
        }
        for(int j=1;j<=cnt;j++){
            if(i*prime[j]>N)break;
            check[i*prime[j]]=true;
            if(i%prime[j]==0)break;
        }
    }
}
vector<int>ve[maxn];
void gao(int id,int val){
    ve[id].clear();
    for(int i=1;prime[i]*prime[i]<=val&&i<=cnt;i++){
        if(val%prime[i]==0){
            ve[id].push_back(prime[i]);
            while(val%prime[i]==0)val/=prime[i];
        }
    }
    if(val!=1)ve[id].push_back(val);
}
int Laxt[maxn],Next[maxn],To[maxn],res;

void add(int u,int v){
    Next[++res]=Laxt[u];Laxt[u]=res;To[res]=v;
}

int ans[maxn],dep[maxn];
map<int,vector<int> >mp;

void dfs(int u,int fa,int depp){
    ans[u]=-1,dep[u]=depp;
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(mp[v].size()==0){
            mp[v].push_back(u);
        }
        else{
            if(ans[u]==-1||dep[ans[u]]<dep[mp[v][mp[v].size()-1]])
                ans[u]=mp[v][mp[v].size()-1];
            mp[v].push_back(u);
        }
    }
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i];
        if(v==fa)continue;
        dfs(v,u,depp+1);
    }
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        mp[v].erase(mp[v].end()-1);
    }
}

int main(){
    init(2e6+10);
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),gao(i,a[i]);

    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }

    dfs(1,-1,1);
    while(q--){
        int op,x,y;
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&x);
            printf("%d\n",ans[x]);
        }
        else{
            scanf("%d%d",&x,&y);
            a[x]=y;
            gao(x,a[x]);
            dfs(1,-1,1);
        }
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+50;
int Laxt[maxn],Next[maxn<<1],To[maxn<<1],cnt;

void add(int u,int v){
    Next[++cnt]=Laxt[u];Laxt[u]=cnt;To[cnt]=v;
}

int n,q;
int a[maxn];
int ans[maxn];
vector<int>Q[maxn];
vector<int>St;

void dfs(int u,int fa){
    int k=-1;
    if(!Q[u].empty()){
        for(int i=St.size()-1;i>=0;i--){
            int v=St[i];
            if(__gcd(a[u],a[v])!=1){
                k=v;break;
            }
        }
        for(int i=0;i<Q[u].size();i++)ans[Q[u][i]]=k;
        Q[u].clear();
    }
    St.push_back(u);
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i];
        if(v==fa)continue;
        dfs(v,u);
    }
    St.pop_back();
}

int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    int res=0;
    for(int i=1;i<=q;i++){
        int op,x,y;
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&x);
            Q[x].push_back(i);
            res++;
        }
        else{
            if(res)dfs(1,-1);
            ans[i]=-10086;
            scanf("%d%d",&x,&y);
            a[x]=y;
            res=0;
        }
    }
    if(res)dfs(1,-1);
    for(int i=1;i<=q;i++)if(ans[i]!=-10086)printf("%d\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/luowentao/p/10556248.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值