码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #638 (Div. 2)

时间:2020-05-23 18:48:16      阅读:54      评论:0      收藏:0      [点我收藏+]

标签:begin   维护   opened   ack   col   第一个   node   字符串   sci   

Codeforces Round #638 (Div. 2)

B. Phoenix and Beauty

正确解法:

n个数分别为ai,往里面任意加数(正数)使连续k个字串的和都相同。

 

如果n个数里面出现数的次数大于k,那么就不能成立。

如果n个数里面出现的数等于k,把这些数按一定顺序输出n次就可。

如果n个数里面出现的数小于k,往里面加1使其等于k。

技术图片
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <set>
 6 #include <queue>
 7 #include <stack>
 8 #include <string>
 9 #include <cstring>
10 #include <vector>
11 #include <map>
12 #include<ctime>
13 //#include <unordered_map>
14 #define mem( a ,x ) memset( a , x ,sizeof(a) )
15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ )
16 #define lson  l ,mid ,pos<<1
17 #define rson mid+1 ,r ,pos<<1|1
18 using namespace std;
19 typedef long long ll ;
20 typedef pair<int ,int> pii;
21 typedef pair<ll ,int> pli;
22 const int inf = 0x3f3f3f3f;
23 const ll mod=998244353;
24 const int N=100000+50;
25 int T,n,k;
26 int a[110],bok[110],cnt=0,b[110],kkk=0;
27 int main()
28 {
29     scanf("%d",&T);
30     while(T--)
31     {
32         scanf("%d%d",&n,&k);
33         int maxx=0;
34         cnt=0;
35         kkk=0;
36         for(int i=1;i<=100;i++)
37             bok[i]=0;
38         for(int i=1;i<=n;i++)
39         {
40             scanf("%d",&a[i]);
41             bok[a[i]]++;
42             if(bok[a[i]]==1)    cnt++;
43         }
44         if(cnt>k)
45         {
46             printf("-1\n");
47             continue;
48         }
49         while(cnt<k)
50         {
51             b[++kkk]=1;
52             cnt++;
53         }
54         for(int i=1;i<=n;i++)
55             if(bok[i])
56             {
57                 b[++kkk]=i;
58             }
59         printf("%d\n",k*n);
60         while(n--)
61         {
62             for(int i=1;i<=kkk;i++)
63                 printf("%d ",b[i]);
64         }
65         printf("\n");
66     }
67  
68  
69     return 0;
70 }
View Code

C. Phoenix and Distribution

正确解法:

把长度为n的字符串分成k个字符串,求其中最大的 最小字典序 的字符串。

 

当aabb分成2份时, ab ab 

当aabbb 分成3份时, b是答案。 (ab/abb/a)都小于b

 

当前面的k个字母都不相同时,单独一个a[k]就是答案。(后面的字符串都可以加到第一个字母上去,总之比a[k]要小)

当前面k个字母都相同时:

  当后面(k+1,n)个字母都不相同时,答案就为a(k,n) 

  当后面(k+1,n)个字母都相同时,平分字符串就好了。

技术图片
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <set>
 6 #include <queue>
 7 #include <stack>
 8 #include <string>
 9 #include <cstring>
10 #include <vector>
11 #include <map>
12 #include<ctime>
13 //#include <unordered_map>
14 #define mem( a ,x ) memset( a , x ,sizeof(a) )
15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ )
16 #define lson  l ,mid ,pos<<1
17 #define rson mid+1 ,r ,pos<<1|1
18 using namespace std;
19 typedef long long ll ;
20 typedef pair<int ,int> pii;
21 typedef pair<ll ,int> pli;
22 const int inf = 0x3f3f3f3f;
23 const ll mod=998244353;
24 const int N=1e5+50;
25 int T,n,k;
26 char s[N],ss[N];
27 int len=0,cnt=0;
28  
29 int main()
30 {
31     scanf("%d",&T);
32     while(T--)
33     {
34         scanf("%d%d",&n,&k);
35         scanf("%s",s+1);
36         sort(s+1,s+n+1);
37         cnt=0;
38         for(int i=1;i<k;i++)
39             if(s[i]!=s[k])
40                 {cnt=1;break;}
41         if(cnt)
42         {
43             printf("%c\n",s[k]);
44             continue;
45         }
46         for(int i=k+2;i<=n;i++)
47             if(s[i]!=s[k+1])
48                 {cnt=1;break;}
49         if(cnt)
50         {
51             printf("%c",s[k]);
52             for(int i=k+1;i<=n;i++)
53                 printf("%c",s[i]);
54             printf("\n");
55         }
56         else
57         {
58             int res=(n-k)%k;
59             printf("%c",s[k]);
60             for(int i=1;i<=(n-k)/k;i++)
61                 printf("%c",s[k+1]);
62             if(res) printf("%c",s[k+1]);
63             printf("\n");
64         }
65     }
66  
67     return 0;
68 }
View Code

D. Phoenix and Science

正确解法:

第一天有1个细菌质量为1.

白天细菌可以不分裂,或者全部分裂,或者部分分裂。

晚上每个细菌增加质量为1.

求达到质量为n的最快天数 和每一天分裂的细胞数量。

 

如果分裂,增加的质量为2,不分裂,增加的质量为1

假设全部分裂,这是增加质量最快的方法。第n天就为 2^n 质量。

就把 1 2 4 …… 总和放进数组里面,再放进去一个 n-sum 。

排序一下,就是每天的细菌数量。

就是前面都是全部分裂,有一天部分分裂。后来都部分分裂。总和就能刚好为n。

 

每一天分裂的细胞数量就为 f[i]-f[i-1]

技术图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <algorithm>
  5 #include <set>
  6 #include <queue>
  7 #include <stack>
  8 #include <string>
  9 #include <cstring>
 10 #include <vector>
 11 #include <map>
 12 #include<ctime>
 13 //#include <unordered_map>
 14 #define mem( a ,x ) memset( a , x ,sizeof(a) )
 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ )
 16 #define lson  l ,mid ,pos<<1
 17 #define rson mid+1 ,r ,pos<<1|1
 18 using namespace std;
 19 typedef long long ll ;
 20 typedef pair<int ,int> pii;
 21 typedef pair<ll ,int> pli;
 22 const int inf = 0x3f3f3f3f;
 23 const ll mod=998244353;
 24 const int N=1e5+50;
 25 int n,lll[2*N],rrr[2*N];
 26 vector<pair<int,int> >ve[2*N];
 27 int ans[2*N],p[2*N];
 28 struct node
 29 {
 30     int id,val;
 31 }tree[8*N];
 32 void build(int x,int l,int r)
 33 {
 34     if(l==r)
 35     {
 36         tree[x].id=p[l];
 37         tree[x].val=lll[p[l]];
 38         return ;
 39     }
 40     int mid=l+r>>1;
 41     build(x<<1,l,mid);
 42     build(x<<1|1,mid+1,r);
 43     if(tree[x<<1].val>tree[x<<1|1].val)
 44         tree[x]=tree[x<<1|1];
 45     else
 46         tree[x]=tree[x<<1];
 47 }
 48 pair<int,int>query(int rt,int l,int r,int L,int R)
 49 {
 50     if(L<=l&&r<=R)
 51     {
 52         return {tree[rt].val,tree[rt].id};
 53     }
 54     int mid=l+r>>1;
 55     pair<int,int>tmp1,tmp2;
 56     tmp1.first=-1;
 57     tmp2.first=-1;
 58     if(mid>=L)  tmp1=query(rt<<1,l,mid,L,R);
 59     if(mid+1<=R)    tmp2=query(rt<<1|1,mid+1,r,L,R);
 60     if(tmp1.first==-1)  return tmp2;
 61     if(tmp2.first==-1)  return tmp1;
 62     if(tmp1.first>tmp2.first)   return tmp2;
 63     else    return tmp1;
 64 }
 65 int main()
 66 {
 67     scanf("%d",&n);
 68     for(int i=1;i<=n;i++)
 69     {
 70         scanf("%d%d",&lll[i],&rrr[i]);
 71         ve[lll[i]].push_back({rrr[i],i});
 72     }
 73     set<pair<int,int> >st;
 74     for(int i=1;i<=n;i++)
 75     {
 76         st.insert(ve[i].begin(),ve[i].end());
 77         int y=(*st.begin()).second;
 78         st.erase(st.begin());
 79         ans[y]=i;
 80         p[i]=y;
 81     }
 82    /* for(int i=1;i<=n;i++)
 83         cout<<ans[i]<<" ";
 84     cout<<endl;*/
 85     build(1,1,n);
 86     for(int i=1;i<=n;i++)
 87     {
 88         if(i+1>rrr[p[i]])   continue;
 89         pair<int,int>k=query(1,1,n,i+1,rrr[p[i]]);
 90         if(k.first<=i)
 91         {
 92             printf("NO\n");
 93             for(int i=1;i<=n;i++)
 94                 cout<<ans[i]<<" ";
 95             cout<<endl;
 96             swap(ans[p[i]],ans[k.second]);
 97              for(int i=1;i<=n;i++)
 98                 cout<<ans[i]<<" ";
 99             cout<<endl;
100             return 0;
101         }
102     }
103     printf("YES\n");
104     for(int i=1;i<=n;i++)
105                 cout<<ans[i]<<" ";
106             cout<<endl;
107 
108     return 0;
109 }
View Code

 

E. Phoenix and Berries

正确解法:

有n棵树,每棵树上面有ai个红苹果和bi个蓝苹果。

每个篮子能装k个苹果,但是篮子只能装红苹果或者蓝苹果或者属于一颗树上面的苹果。

求最多能把多少个篮子装满。

 

根据贪心,我们应该选择尽可能多的颜色相同的苹果装进篮子里,对于一颗树来说,装不同颜色的篮子只可能有一个。其他都可以化成一个的情况。

设f[i][j]表示装完第i棵树时,剩下的红苹果的数量为j. 剩下蓝苹果的数量为 果实总数-f[i][j]*k-j.

设第i棵树的篮子由s1个红苹果和k-s1个蓝苹果组成。

未装的红苹果数量 num1=j+ai-s1  未装的蓝苹果数量为 num2=sum-f[i][j]*k-num1-k 

f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k+1);

当这颗树不装不同颜色时 :

  num1=j+a[i],num2=sum-f[i-1][j]*k-j-a[i];

         f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k);

 

然后!!!  int取模比ll 快一个常数,以后尽量用int 来取模,不然就可能会tle.

 

技术图片
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <set>
 6 #include <queue>
 7 #include <stack>
 8 #include <string>
 9 #include <cstring>
10 #include <vector>
11 #include <map>
12 #include<ctime>
13 //#include <unordered_map>
14 #define mem( a ,x ) memset( a , x ,sizeof(a) )
15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ )
16 #define lson  l ,mid ,pos<<1
17 #define rson mid+1 ,r ,pos<<1|1
18 using namespace std;
19 typedef long long ll ;
20 typedef pair<int ,int> pii;
21 typedef pair<ll ,int> pli;
22 const int inf = 0x3f3f3f3f;
23 const ll mod=998244353;
24 const int N=100000+50;
25 int n,k;
26 int a[550],b[550];
27 ll f[550][550],sum=0;
28 int num1,num2;
29 int main()
30 {
31     scanf("%d%d",&n,&k);
32     for(int i=1;i<=n;i++)
33         scanf("%d%d",&a[i],&b[i]);
34     memset(f,-1,sizeof(f));
35     f[0][0]=0;
36     for(int i=1;i<=n;i++)
37     {
38         sum+=a[i]+b[i];
39         for(int j=0;j<k;j++)
40         {
41             if(f[i-1][j]<0) continue;
42             for(int s1=1;s1<k&&s1<=a[i];s1++)
43             {
44                 if(k-s1>b[i])   continue;
45                 num1=j+a[i]-s1;
46                 num2=sum-f[i-1][j]*k-num1-k;
47                 f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k+1);
48             }
49             num1=j+a[i],num2=sum-f[i-1][j]*k-j-a[i];
50             f[i][num1%k]=max(f[i][num1%k],f[i-1][j]+num1/k+num2/k);
51         }
52     }
53     ll ans=0;
54     for(int i=0;i<k;i++)
55         ans=max(ans,f[n][i]);
56     printf("%lld\n",ans);
57  
58     return 0;
59 }
View Code

 

 

F. Phoenix and Memory

正确解法:

1-n有一个特定的顺序,可是现在忘了顺序。

只记得每个数 在 l[i]-r[i] 之间。求特定顺序,并且看是否顺序唯一。

已知每个数范围,如何求特定顺序呢?

用ve[l].push_back({r,i});

看每个l 最小的那个区间,依次排序取值就可以了。

 

 1 for(int i=1;i<=n;i++)
 2     {
 3         scanf("%d%d",&lll[i],&rrr[i]);
 4         ve[lll[i]].push_back({rrr[i],i});
 5     }
 6     set<pair<int,int> >st;
 7     for(int i=1;i<=n;i++)
 8     {
 9         st.insert(ve[i].begin(),ve[i].end());
10         int y=(*st.begin()).second;
11         st.erase(st.begin());
12         ans[y]=i;
13         p[i]=y;
14     }

 

 

那么如何求唯一呢?

若 编号为2 的区间为[1,3] ,编号为3 的区间为 [1,3]

那么 2在1位置,3在2位置 。和 2在2位置,3在1位置都可以满足。

p[2]=1,p[3]=2;  l[2]=1,r[2]=3;  l[3]=1,r[3]=3;

得: l[p[j]] <= i < j <= r[p[i]]

得到结果:对于编号为i的来说,如果能找到一个编号属于 [i+1,r[p[i]]] 区间的 且 l[p[j]] <=i 那么就可以交换顺序。

当然只要 for 两次就可以得到。

但是会超时怎么办呢? 

用线段树来维护。

 

技术图片
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <algorithm>
  5 #include <set>
  6 #include <queue>
  7 #include <stack>
  8 #include <string>
  9 #include <cstring>
 10 #include <vector>
 11 #include <map>
 12 #include<ctime>
 13 //#include <unordered_map>
 14 #define mem( a ,x ) memset( a , x ,sizeof(a) )
 15 #define rep( i ,x ,y ) for( int i = x ; i<=y ;i++ )
 16 #define lson  l ,mid ,pos<<1
 17 #define rson mid+1 ,r ,pos<<1|1
 18 using namespace std;
 19 typedef long long ll ;
 20 typedef pair<int ,int> pii;
 21 typedef pair<ll ,int> pli;
 22 const int inf = 0x3f3f3f3f;
 23 const ll mod=998244353;
 24 const int N=1e5+50;
 25 int n,lll[2*N],rrr[2*N];
 26 vector<pair<int,int> >ve[2*N];
 27 int ans[2*N],p[2*N];
 28 struct node
 29 {
 30     int id,val;
 31 }tree[8*N];
 32 void build(int x,int l,int r)
 33 {
 34     if(l==r)
 35     {
 36         tree[x].id=p[l];
 37         tree[x].val=lll[p[l]];
 38         return ;
 39     }
 40     int mid=l+r>>1;
 41     build(x<<1,l,mid);
 42     build(x<<1|1,mid+1,r);
 43     if(tree[x<<1].val>tree[x<<1|1].val)
 44         tree[x]=tree[x<<1|1];
 45     else
 46         tree[x]=tree[x<<1];
 47 }
 48 pair<int,int>query(int rt,int l,int r,int L,int R)
 49 {
 50     if(L<=l&&r<=R)
 51     {
 52         return {tree[rt].val,tree[rt].id};
 53     }
 54     int mid=l+r>>1;
 55     pair<int,int>tmp1,tmp2;
 56     tmp1.first=-1;
 57     tmp2.first=-1;
 58     if(mid>=L)  tmp1=query(rt<<1,l,mid,L,R);
 59     if(mid+1<=R)    tmp2=query(rt<<1|1,mid+1,r,L,R);
 60     if(tmp1.first==-1)  return tmp2;
 61     if(tmp2.first==-1)  return tmp1;
 62     if(tmp1.first>tmp2.first)   return tmp2;
 63     else    return tmp1;
 64 }
 65 int main()
 66 {
 67     scanf("%d",&n);
 68     for(int i=1;i<=n;i++)
 69     {
 70         scanf("%d%d",&lll[i],&rrr[i]);
 71         ve[lll[i]].push_back({rrr[i],i});
 72     }
 73     set<pair<int,int> >st;
 74     for(int i=1;i<=n;i++)
 75     {
 76         st.insert(ve[i].begin(),ve[i].end());
 77         int y=(*st.begin()).second;
 78         st.erase(st.begin());
 79         ans[y]=i;
 80         p[i]=y;
 81     }
 82    /* for(int i=1;i<=n;i++)
 83         cout<<ans[i]<<" ";
 84     cout<<endl;*/
 85     build(1,1,n);
 86     for(int i=1;i<=n;i++)
 87     {
 88         if(i+1>rrr[p[i]])   continue;
 89         pair<int,int>k=query(1,1,n,i+1,rrr[p[i]]);
 90         if(k.first<=i)
 91         {
 92             printf("NO\n");
 93             for(int i=1;i<=n;i++)
 94                 cout<<ans[i]<<" ";
 95             cout<<endl;
 96             swap(ans[p[i]],ans[k.second]);
 97              for(int i=1;i<=n;i++)
 98                 cout<<ans[i]<<" ";
 99             cout<<endl;
100             return 0;
101         }
102     }
103     printf("YES\n");
104     for(int i=1;i<=n;i++)
105                 cout<<ans[i]<<" ";
106             cout<<endl;
107 
108     return 0;
109 }
View Code

 

Codeforces Round #638 (Div. 2)

标签:begin   维护   opened   ack   col   第一个   node   字符串   sci   

原文地址:https://www.cnblogs.com/Kaike/p/12943562.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!