Fork me on GitHub

ACM团队周赛题解(3)

940和822两套div.2

老规矩

#define MAXN 1000000+5
#define MOD 1000000007
#define PI (acos(-1.0))
#define EPS 1e-6
#define MMT(s,a) memset(s, a, sizeof s)
#define GO(i,a,b) for(int i = (a); i < (b); ++i)
#define GOE(i,a,b) for(int i = (a); i <= (b); ++i)
#define OG(i,a,b) for(int i = (a); i > (b); --i)
#define OGE(i,a,b) for(int i = (a); i >= (b); --i)


 

A - Points on the line(940A)

 

题意:问最少删除几个数字,使得剩余数字的 最大值   -   最小值 < = m;

 

思路:思维逆向,求符合题意的最多数字

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int a[105]={0};
 4 int main(){
 5     int n,d,cnt=-9999999;
 6     cin>>n>>d;
 7     for(int i=0;i<n;i++){
 8         cin>>a[i];
 9     }
10     sort(a,a+n);
11     for(int i=0;i<n;i++){
12         for(int j=0;j<n;j++){
13             if(a[j]-a[i]<=d) cnt=max(cnt,j-i+1);
14         }
15     }
16     cout<<n-cnt<<endl;
17     return 0;
18 }

 

B - Our Tanya is Crying Out Loud

题意:从n走到1,两种走法,从n走到n-1,花费a;从n走到n/k,花费b,问最小花费

思路:最开始还想成BFS了,不需要BFS,因为每次都是从n往1走,只需要对比一下下一步两种花费哪种最小就行了。特判一下k==1的情况。

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     cin>>n>>k>>a>>b;
 4     if(k == 1){
 5         cout << (n-1)*a << endl;
 6     }
 7     else{
 8         ll ans = 0;
 9         while(n > 1){
10             if(n%k){
11                 int m = n%k;
12                 n -= m;
13                 if(n<1)
14                     ans += a*(m-1);
15                 else
16                     ans += a*m;
17             }
18             else{
19                 int m = n/k;
20                 if((n-m)*a < b)
21                     ans += (n-m)*a;
22                 else
23                     ans += b;
24                 n = m;
25             }
26         }
27         cout << ans << endl;
28     }
29     return 0;
30 }

 

C - Phone Numbers

题意:给你一个长度为n的字符串,然后让你构造一个长度为m的字符串,只能用n中的字符,可重复,输出m的全排列中字典序比n大的第一个。方便理解,我解释一下第一个样例,n = abc,用这个字符串中的元素构成的长度为3的字符串有很多,比如

aaa, aab, aac, aba, abb, abc, aca, acb.......,然后会发现比abc大的第一个就是aca,所以输出aca。

思路:先分两种情况

当n < m时,这时候只需要在n字符串的后面加m-n个最小字符就行了,因为这就是字典序比n字符串大的第一个字符串。

当n >= m时,首先Hash一下n字符串,这时候我们只需要在n字符串中选取m长度的字符串,然后对这个字符串进行+1操作,也就是把字符串看成k进制数,通过前面的Hash表,进行+1,这样就保证了得到的字符串为m长度,而且是大于n字符串的第一个字符串。

 1 map<char,int> Hsh;
 2 map<int,char> Exhsh;
 3 int k;
 4 char ch1,ch2;
 5 
 6 void gethash(string s){
 7     string ss(s);
 8     s.erase(unique(s.begin(),s.end()),s.end());
 9     sort(s.begin(),s.end());
10     ch1 = s[0];
11     ch2 = s[s.size()-1];
12     int len = s.size();
13     GO(i,0,len){
14         Hsh[s[i]] = i;
15         Exhsh[i] = s[i];
16     }
17     //cout << num << endl;
18 }
19 
20 int main(){
21     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
22     int n,m;
23     string s;
24     cin>>n>>m>>s;
25     if(m > n){
26         cout << s;
27         sort(s.begin(),s.end());
28         ch1 = s[0];
29         GO(i,n,m){
30             cout << ch1;
31         }
32         cout << endl;
33     }
34     else{
35         gethash(s);
36         string ss = s.substr(0,m);
37         int flag = 0;
38         OGE(i,m-1,0){
39             if(i == m-1){
40                 if(ss[i] < ch2){
41                     ss[i] = Exhsh[Hsh[ss[i]]+1];
42                     flag = 0;
43                 }
44                 else{
45                     ss[i] = ch1;
46                     flag = 1;
47                 }
48             }
49             else if(!flag)
50                 break;
51             else{
52                 if(ss[i] < ch2){
53                     ss[i] = Exhsh[Hsh[ss[i]]+1];
54                     flag = 0;
55                 }
56                 else{
57                     ss[i] = ch1;
58                     flag = 1;
59                 }
60             }
61         }
62         cout << ss << endl;
63     }
64 
65     return 0;
66 }

 

D - Alena And The Heater

题意就是给你一串a,一串b,然后满足下面关系式

 

  •  当 ai, ai - 1, ai - 2, ai - 3, ai - 4 > r 而且 bi - 1 = bi - 2 = bi - 3 = bi - 4 = 1时,bi = 0
  •  当 ai, ai - 1, ai - 2, ai - 3, ai - 4 < l 而且 bi - 1 = bi - 2 = bi - 3 = bi - 4 = 0时, bi = 1
  •  其他情况bi = bi - 1

然后就是让你去找一对满足题意的 l 和 r 。

思路:按照题目的要求,不断缩进l和r的范围即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=100000+10;
 4 const int INF=1e+9;
 5 const int NINF=-1e+9;
 6 int a[maxn],b[maxn];
 7 string s;
 8 int l,r;
 9 int main(){
10     int n;
11     cin>>n;
12     l=NINF,r=INF;
13     for(int i=0;i<n;i++){
14         cin>>a[i];
15     }
16     cin>>s;
17     for(int i=0;i<s.size();i++){
18         b[i]=s[i]-'0';
19     }
20     for(int i=4;i<n;i++){
21         if(b[i]==1&&b[i-1]==0&&b[i-2]==0&&b[i-3]==0&&b[i-4]==0){
22             l=max(l,max(a[i]+1,max(a[i-1]+1,max(a[i-2]+1,max(a[i-3]+1,a[i-4]+1)))));
23      }
24         else if(b[i]==0&&b[i-1]==1&&b[i-2]==1&&b[i-3]==1&&b[i-4]==1){
25             r=min(r,min(a[i]-1,min(a[i-1]-1,min(a[i-2]-1,min(a[i-3]-1,a[i-4]-1)))));
26         }
27     }
28     cout<<l<<" "<<r<<endl;
29     return 0;
30 }

 

F - I'm bored with life

题意:求GCD(a!,b!);

思路:GCD(a!,b!) = min(a!,b!) = (min(a,b))!;

 1 ll f(int n){
 2     if(n == 1)
 3         return 1;
 4     return n*f(n-1);
 5 }
 6 
 7 int main(){
 8     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 9     int a,b;
10     cin>>a>>b;
11     int n = min(a,b);
12     cout << f(n) << endl;
13     return 0;
14 }

 

G - Crossword solving

题意:就是当把某个字符换成?就代表可以匹配任何字符,问要使得a串在b串中匹配到,最少需要变几个位置,并输出位置;

思路:暴力找a在b每一个位置需要变换几个字符,并存下位置,然后输出最小变换即可。

#define PB push_back

 1 int main(){
 2     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
 3     int n,m;
 4     int minn = INT_MAX,ii;
 5     vector<int> q[1005];
 6     string s1,s2;
 7     int num[1005] = {0};
 8     cin>>m>>n;
 9     cin>>s1>>s2;
10     GOE(i,0,n-m){
11         GO(j,0,m){
12             if(s1[j] != s2[i+j]){
13                 num[i]++;
14                 q[i].PB(j+1);
15             }
16         }
17     }
18     GOE(i,0,n-m){
19         if(num[i] < minn){
20             minn = num[i];
21             ii = i;
22         }
23     }
24     cout << minn << endl;
25     for(auto &it:q[ii]){
26         cout << it << ' ';
27     }
28     cout << endl;
29 
30     return 0;
31 }

 

H - Hacker, pack your bags!

题意:给你一堆时间开始点和结束点,以及花费,问要k小时需要的最小花费,时间不能重叠。

思路:先对所有时间点排序,然后遍历每个时间点的,例如对于第i个,连续时间为x,则去找k-x时间是否存在且满足题意,跟新最小花费,同时用另一个数组维护每个时间段的最小花费。这里排序利用了Tuple的特性所以不需要重构比较函数

#define PB push_back
#define MP make_pair
#define MT make_tuple

 1 vector<tuple<int,int,int>> op;
 2 
 3 int N, X;
 4 int L[210000], R[210000], cost[210000];
 5 
 6 int dp[210000];
 7 int ans = -1;
 8 
 9 int main(){
10     ios_base::sync_with_stdio(false), cout.tie(0), cin.tie(0);
11     cin>>N>>X;
12     GO(i,0,N){
13         cin>>L[i]>>R[i]>>cost[i];
14         op.PB(MT(L[i], 0, i));
15         op.PB(MT(R[i], 1, i));
16     }
17     sort(op.begin(), op.end());
18     int len = op.size();
19     GO(i,0,len){
20         int o = get<1>(op[i]), ind = get<2>(op[i]);
21         if(o == 0){   //如果是开始时间点
22             int dur = R[ind] - L[ind] + 1, nec = X - dur;
23             if(nec < 0 || dp[nec] == 0)   //如果x-d这段时间不存在
24                 continue;
25             if(ans == -1 || ans > dp[nec] + cost[ind])  //更新花费
26                 ans = dp[nec] + cost[ind];
27         }
28         else{    //如果是结束时间点
29             int dur = R[ind] - L[ind] + 1;
30             if(dp[dur] == 0 || dp[dur] > cost[ind])  //如果这个时间没有使用或者有更小的花费,更新花费
31                 dp[dur] = cost[ind];
32         }
33     }
34     cout << ans << endl;
35     return 0;
36 }

 

posted @ 2018-09-28 08:59  Xenny  阅读(590)  评论(0编辑  收藏  举报