Codeforces Round #595 (Div. 3)

 第一次這麼順手。。。都是1A。。。。D想了1個小時,想了一個假算法。。。最後20分開E,我叼,簡單DP???不負衆望的10分鐘A掉。。。node

 

A. Yet Another Dividing into Teams 只會有兩個隊c++

 B1.B2. Books Exchange直接DFS找環,環內的傳遞時間是同樣的。標記一下,線性複雜度。算法

 C1. Good Numbers (easy version) 其實就是3進製表示形式不能有2,那麼簡單版本直接預處理1-1000而後找第一個大於n的數便可。ide

#include<bits/stdc++.h>
#define LL long long
using namespace std;
vector<int>ans;
bool check(int x){
   int flag=0;
   while(x){
     if (x%3==2){
        flag=1;
        break;
     }
     x=x/3;
   }
   if (flag==1)return 0;
   else return 1;
}
void init(){
  for (int i=1;i<=19683;i++){
     if(check(i)){
        ans.push_back(i);
     }
  }
}
int main(){
  int t,n;
  scanf("%d",&t);
  init();
  while(t--){
     scanf("%d",&n);
     int pos=lower_bound(ans.begin(),ans.end(),n)-ans.begin();
     printf("%d\n",ans[pos]);
  }
  return 0;
}
View Code

 C2. Good Numbers (hard version) 咱們比較容易求出最大小於n的數,由於咱們能夠從3的高位往低位試。而後從地位到高位,把第一個3進制位爲0的位置變成1,其後位置所有變成0,就是恰好大於等於n的三進制沒有2的。spa

#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL n;
LL qpow(LL a,LL b)
{
    LL ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a;
        a=a*a;
        b=b/2;
    }
    return ans;
}
int vis[50];
int main()
{
    int t;
    LL s=1e18;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld",&n);
        LL ans=0;
        memset(vis,0,sizeof(vis));
        for (int i=38;i>=0;i--)
        {
            if (ans+qpow(3,i)<n){
                ans+=qpow(3,i);
                vis[i]=1;
            }
        }
        for (int i=0;i<=38;i++){
            if (vis[i]==1){
                ans-=qpow(3,i);
            }else {
                ans+=qpow(3,i);
                break;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

  D1.D2. Too Many Segments 看錯題了,我一直覺得要保證整個區間是連續的。。。。發現其實只要區間的覆蓋次數<k次就行,這樣的話,其實就很簡單了,把區間排序,放入一個mutilset裏面,裏面維護全部有相交區間的覆蓋,而後判斷mutilset是否是大於k個,若是是必定要丟,怎麼丟比較優雅???反正最左邊已經保證了覆蓋次數<k,那麼丟區間的右端點最遠的,這樣對後面影響也最小。3d

#include<bits/stdc++.h>
#define pii pair<int,int>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define mp make_pair
#define pb push_back
using namespace std;
const int maxx = 2e5+6;
multiset<pii>s;
vector<int>ans;
struct node{
   int l,r,id;
}p[maxx];
bool cmp(node a,node b){
   return a.l<b.l;
}
int main(){
  int n,k;
  while(~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;
     }
     ans.clear();
     sort(p+1,p+1+n,cmp);
     rep(i,1,n){
        ///s裏面最小的r小於p[i].l表明二者已經不相連了
        while(s.size() && (*s.begin()).first<p[i].l)s.erase(s.begin());
        s.insert(mp(p[i].r,p[i].id));
        ///這裏s表明重複裏面每一段都有重複部分 若是重複部分大於K了
        ///確定刪除最右邊的,由於最左邊的已經知足小於k了,刪除最右邊的,使得後面出現>k的機率變小了
        while(s.size()>k){
            auto it=s.end();
            it--;
            ans.pb((*it).second);
            s.erase(it);
        }
     }
     int sz=ans.size();
     printf("%d\n",sz);
     for (int i=0;i<sz;i++){
        if(i)printf(" %d",ans[i]);
        else printf("%d",ans[i]);
     }
     printf("\n");
  }
  return 0;
}
View Code

  E.簡單DP,每層必定是由上一層轉移過來,因此很簡單了。code

 #include<bits/stdc++.h>
#define LL long long
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxx = 2e5+6;
LL a[maxx];
LL b[maxx];
LL n,c;
LL dp[maxx][3];
int main(){
   while(~scanf("%lld%lld",&n,&c)){
       for (int i=2;i<=n;i++){
          scanf("%lld",&a[i]);
       }
       for (int i=2;i<=n;i++){
          scanf("%lld",&b[i]);
       }
       dp[1][1]=0;
       dp[1][2]=c;
       for (int i=2;i<=n;i++){
          dp[i][1]=min(dp[i-1][1]+a[i],dp[i-1][2]+a[i]);
          dp[i][2]=min(dp[i-1][2]+b[i],dp[i-1][1]+b[i]+c);
       }
       for (int i=1;i<=n;i++){
          if (i-1)printf(" %lld",min(dp[i][1],dp[i][2]));
          else printf("0");
       }
       printf("\n");
   }
}
View Code

  F.真~神仙題,樹有點權,問選出一個集合,使得集合內部全部點的距離>=k,而且點權和最大。。。blog

  樹形DP作法。。。看了2個小時自閉了。。。等牛逼網友發博客再說排序

  貪心:咱們考慮選擇某個的貢獻,咱們首先安裝深度從下往上進行遍歷,而後對於每次選擇i,咱們把這個點全部距離<=k的點,減去a[i],表明選擇了這個點,若是某個點的值>0,表明這個點比i更優秀???咱們能夠直接加上a[j]表明選擇j,因爲咱們算的是貢獻,因此直接把周圍的點的全部能到的點的所有減去便可。博客

#include<bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
const int maxx = 1005;
int ver[maxx],Next[maxx],head[maxx];
int vis[maxx];
int a[maxx];
int n,k,tot;
vector<int>b;
void add(int x,int y){
  ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
  ver[++tot]=x;Next[tot]=head[y];head[y]=tot;
}
void bfs(int st){
   queue<pii>q;
   q.push(mp(st,0));
   while(q.size()){
       int u=q.front().first;
       int dep=q.front().second;
       b.pb(u);
       q.pop();
       vis[u]=1;
       for (int i=head[u];i;i=Next[i]){
          int v=ver[i];
          if (!vis[v]){
            q.push(mp(v,dep+1));
          }
       }
   }
}
int dfs(int x){
    for (int i=1;i<=n;i++){
        vis[i]=0;
    }
    queue<pii>q;
    while(q.size())q.pop();
    q.push(mp(x,0));
    int c=a[x];
    while(q.size()){
        int u=q.front().first;
        a[u]-=c;
        vis[u]=1;
        int dep=q.front().second;
        q.pop();
        for (int i=head[u];i;i=Next[i]){
            int v=ver[i];
            if (vis[v])continue;
            if (dep<k){
                q.push(mp(v,dep+1));
            }
        }
    }
    return c;
}
int main(){
    while(~scanf("%d%d",&n,&k)){
        for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        int uu,vv;
        for (int i=1;i<n;i++){
            scanf("%d%d",&uu,&vv);
            add(uu,vv);
        }
        bfs(1);
        reverse(b.begin(),b.end());
        int sz=b.size();
        int ans=0;
        for (int i=0;i<sz;i++){
            if (a[b[i]]>0)ans+=dfs(b[i]);
        }
        printf("%d\n",ans);
    }
   return 0;
}
View Code
相關文章
相關標籤/搜索