CF595 Div31249A,1249B1,1249B2,1249C1,1249C2,1249D1,1249D2,1249E,1249F)题解

A:水题,先排序,有相连的输出2,否则输出1.

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
typedef long long ll;
const int INF=0x3f3f3f3f;
int q,n;
const int maxn=110;
int a[maxn];
 
 
int main()
{
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i) scanf("%d",a+i);
        sort(a+1,a+1+n);
        int cnt=1;
        for(int i=2;i<=n;++i)
        {
            if(a[i]-a[i-1]==1) {cnt=2;break;}
        }
        printf("%d\n",cnt);
    }
    
    return 0;
}
View Code

B1和B2: 水题:同一个循环里面的步数一样,O(N)跑一遍即可。

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
typedef long long ll;
const int INF=0x3f3f3f3f;
int q,n;
const int maxn=2e5+10;
int p[maxn],cnt[maxn],vis[maxn];
 
 
int main()
{
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i) scanf("%d",p+i),cnt[i]=vis[i]=0;
        for(int i=1;i<=n;++i)
        {
            if(vis[i]) continue;
            int ans=1,num=p[i];vis[i]=i;
            while(num!=i)
            {
                num=p[num];
                vis[num]=i;
                ans++;
            }
            cnt[i]=ans;
        }
        for(int i=1;i<=n;++i) 
            printf("%d%c",cnt[vis[i]],i==n?'\n':' ');
    }
    
    return 0;
}
View Code

C1和C2: 水题:很显然>=n的最大的只要把n里面所有的3的幂去除,然后把剩下未选中的挑一个最小的且比去除之后的n大的加入答案就行。注意到样例里面给的最大的那个是3^38.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[40];
void prework()
{
    a[0]=1;
    for(int i=1;i<=39;++i) a[i]=a[i-1]*3;
}
 
int q;
ll n,cn;
 
int main()
{
    prework();
    scanf("%d",&q);
    while(q--)
    {
        scanf("%lld",&n);
        ll ans=0; cn=n;
        int flag=-1,tmp=-1,tt=0;
        for(int i=38;i>=0;--i) 
        {
            if(n==a[i]){ans=a[i];tt=1;break;}
            if(a[i]<n){tmp=i+1;break;}    
        }
        if(tt){printf("%lld\n",ans);continue;}
        
        for(int i=tmp-1;i>=0;--i)
        {
            if(n==a[i]){ans+=a[i];tt=1;break;}
            if(n>a[i]) {n-=a[i];ans+=a[i];}
            else flag=i; 
        }
        if(tt){printf("%lld\n",ans);continue;}
        
        if(flag!=-1)
        {
            for(int i=0;i<flag;++i) ans-=a[i];
            ans+=a[flag];
        }
        else ans=a[tmp];
    
        printf("%lld\n",ans);
    }
    
    return 0;    
} 
View Code

D1和D2:

D1可以暴力:set维护答案。

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
typedef long long ll;
const int INF=0x3f3f3f3f;
 
const int maxn=210;
int k,n,cnt[maxn],vis[maxn];
struct Node{
    int l,r,id;
}p[maxn];
bool cmp(Node &a,Node &b){return a.r<b.r;}
vector<Node> v[maxn];
set<int> st;
 
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
    { 
        scanf("%d%d",&p[i].l,&p[i].r);p[i].id=i;
        for(int j=p[i].l;j<=p[i].r;++j)
            v[j].push_back(Node{p[i].l,p[i].r,i}),cnt[j]++;
    } 
    //for(int i=1;i<=200;++i) cout<<cnt[i]<<endl;
    for(int i=1;i<=200;++i) 
        sort(v[i].begin(),v[i].end(),cmp);
    for(int i=1;i<=200;++i)
    {
        if(cnt[i]>k) 
        {
            int nn=cnt[i]-k;
            for(int j=v[i].size()-1;j>=0&&nn;--j)
            { 
                if(vis[v[i][j].id]) continue;
                st.insert(v[i][j].id),nn--; 
                vis[v[i][j].id]=1;
                for(int k=v[i][j].l;k<=v[i][j].r;++k)
                    cnt[k]--; 
            } 
        }
    }
    int len=st.size();
    printf("%d\n",len);
    set<int>::iterator it;
    for(it=st.begin();it!=st.end();++it)
        printf("%d ",(*it));
    puts("");
    
        
    return 0;
}
View Code

D2用线段树。按照 r 从小到大排序。然后从i 1-n枚举,如果区间最大值<k,则加入该线段,否则该线段必须去掉,加入答案集合里面即可。

最后依次输出答案;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int res[maxn],ans,s[maxn],add[maxn],x,cnt,k,n,Max;
struct Node{
    int l,r,id;
    bool operator<(const Node&p)const{
        return r^p.r?r<p.r:l<p.l;
    }
}a[maxn];
void pushdown(int l,int r,int rt)
{
    int mid=l+r>>1;
    add[rt<<1]+=add[rt],add[rt<<1|1]+=add[rt];
    s[rt<<1]+=add[rt],s[rt<<1|1]+=add[rt];
    add[rt]=0;
}
void update(int l,int r,int rt,int u,int v)
{
    if(l>v||r<u) return;
    if(l>=u&&r<=v)
    {
        s[rt]+=x,add[rt]+=x;
        return;
    }
    if(add[rt]) pushdown(l,r,rt);
    int mid=l+r>>1;
    update(l,mid,rt<<1,u,v);
    update(mid+1,r,rt<<1|1,u,v);
    s[rt]=max(s[rt<<1],s[rt<<1|1]);
}
void query(int l,int r,int rt,int u,int v)
{ 
    if(l>v||r<u) return;
    if(l>=u&&r<=v)
    { 
        ans=max(ans,s[rt]);
        return;
    }
    if(add[rt]) pushdown(l,r,rt);
    int mid=l+r>>1;
    query(l,mid,rt<<1,u,v);query(mid+1,r,rt<<1|1,u,v);
    s[rt]=max(s[rt<<1],s[rt<<1|1]);
}
int main()
{  
    scanf("%d%d",&n,&k);
    Max=cnt=0;
    for(int i=1;i<=n;++i) 
    {
        scanf("%d%d",&a[i].l,&a[i].r);a[i].id=i; 
        Max=max(Max,a[i].r);    
    }
    
    sort(a+1,a+1+n);x=1;
    for(int i=1;i<=n;++i)
    {
        int u=a[i].l,v=a[i].r; ans=0;
        query(1,Max,1,u,v); 
        if(ans<k) update(1,Max,1,u,v);
        else res[++cnt]=a[i].id;
    }
    printf("%d\n",cnt);
    sort(res+1,res+1+cnt);
    for(int i=1;i<=cnt;++i) 
        printf("%d%c",res[i],i==cnt?'\n':' ');
    return 0;
}
View Code

E:水题:DP即可。设f[i][0],f[i][1]表示选择楼梯和电梯的状态,直接按照题意模拟就行。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int a[N],b[N],f[N][2],n,c;
int main()
{  
    scanf("%d%d",&n,&c);--n;
    for(int i=1;i<=n;++i) scanf("%d",a+i);
    for(int i=1;i<=n;++i) scanf("%d",b+i);
    f[0][1]=1e9;
    for(int i=1;i<=n;++i) f[i][0]=min(f[i-1][0],f[i-1][1])+a[i],f[i][1]=min(f[i-1][0]+c,f[i-1][1])+b[i];
    printf("0 ");for(int i=1;i<=n;++i) printf("%d ",min(f[i][0],f[i][1])); puts("");
    return 0;
}
View Code

F题:暴力贪心。n<=200直接暴力找从深度为n开始距离k以内的点集和。

贪心的取比较大的值即可。
将所有点按照深度从大到小排序,如果当前点点权a[i]大于0,则将距离为k以内的所有点减a[i]
代表取了当前点,为答案贡献a[i]
如果下面又扫到大于零的点权,说明那个点比这个大,于是取那个

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10; 
int n,k,a[maxn],t,nw,u,v,d[maxn],ans;
vector<int> g[maxn];
struct Edge{
    int v,nxt;
} edge[maxn<<1];
int head[maxn],tot;
void AddEdge(int u,int v)
{
    edge[tot].v=v;edge[tot].nxt=head[u];head[u]=tot++;
    edge[tot].v=u;edge[tot].nxt=head[v];head[v]=tot++;
}
void dfs(int x,int fa)
{
    g[d[x]=d[fa]+1].push_back(x);
    for(int i=head[x],j;~i;i=edge[i].nxt)
        if((j=edge[i].v)!=fa) dfs(j,x);
}
void dfs2(int x,int fa,int dep)
{
    a[x]-=nw;
    if(dep==k) return;
    for(int i=head[x],j;~i;i=edge[i].nxt)
        if((j=edge[i].v)!=fa) dfs2(j,x,dep+1);
}
int main()
{  
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i) scanf("%d",a+i),head[i]=-1;
    for(int i=1;i<n;++i) scanf("%d%d",&u,&v),AddEdge(u,v);
    dfs(1,0);
    for(int i=n;i;--i)
        for(int j=0,sz=g[i].size(),x;j<sz;++j)
            if((x=a[g[i][j]])>0) nw=x,ans+=x,dfs2(g[i][j],0,0);
    printf("%d\n",ans);
    return 0;
}
View Code

 

posted @ 2019-10-23 23:59  StarHai  阅读(390)  评论(0编辑  收藏  举报