Codeforces Round #637 (Div. 2) A~D
http://codeforces.com/contest/1341/
A. Nastya and Rice
题意
有 (n) 个范围在 ([a-b,a+b]) 的数字,询问他们的和能否在区间 ([c-d,c+d]) 内。
解题
这 (n) 个数字和的范围是 ([n(a-b),n(a+b)]) ,判断是否与 ([c-d,c+d]) 存在交集即可。
def scanf():
return list(map(int,input().split()))
for t in range(int(input())):
n,a,b,c,d = scanf()
p = n*(a-b); q = n*(a+b)
if(p>c+d or q<c-d): print("NO")
else: print("YES")
B. Nastya and Door
题意
给定一个正整数序列,代表连绵的山脉。序列中如果存在 (a_{i-1}<a_i land a_i>a_{i+1}) 的位置,则称 (a_i) 为山峰。
有一个巨大的门,把这个门水平扔山上问最多能分成几份。这个门或门的碎片,遇到山峰之后就会分成两半。
解题
这个题是真的难翻译,又长又玄幻,不过题目还算简单。
差分,记录位置前面的山峰数量,寻找山峰最多的区间,在这里把门扔下去分成的份数最多,为山峰数(+1) 。
注意下边界的判定,题目中说区间边界的山峰不会分割门。
#include<bits/stdc++.h>
#define ll long long
#define fr(i,n) for(int i=0;i<n;i++)
#define frs(i,n,flag) for(int i=0;i<n&&flag;i++)
#define frr(i,j,n) for(int i=j;i<n;i++)
#define r_frr(i,j,n) for(int i=n-1;i>=j;i--)
#define frrs(i,j,n,flag) for(int i=j;i<n&&flag;i++)
#define r_frrs(i,j,n,flag) for(int i=n-1;i>=j&&flag;i--)
#define arend(i,n) ((i!=n-1)?" ":"
")
#define memset0(dp) memset(dp,0,sizeof(dp))
#define print_arr(begin,end) for(auto it = begin;it!=end;it++) cout<<*it<<arend(it,end);
#define log_this(name,value) cout<<name<<": "<<value<<endl;
#define e4 10004
#define e5 100005
#define e6 1000006
#define e7 10000007
#define e9 1000000000
#define INF 9999999
using namespace std;
int to_int(string s) {stringstream ss;ss<<s;int a;ss>>a;return a;}
string to_str(double a) {stringstream ss;ss<<a;return ss.str();}
int a[2*e5];
int ct[2*e5]; //记录区间 (0,i) 的山峰数量,注意是开区间
int main(){
cin.tie(0);
//ios::sync_with_stdio(false);
//cout<<setiosflags(ios::fixed)<<setprecision(0);
//freopen("1.out","w",stdout);
int t;
while(cin>>t){
while(t--){
int n,k;cin>>n>>k;
fr(i,n) cin>>a[i];
ct[0] = 0;
ct[1] = 0;
frr(i,1,n-1){
ct[i+1] = ct[i];
if(a[i]>a[i-1]&&a[i]>a[i+1]){
ct[i+1]++;
}
}
ct[n] = ct[n-1];
int ans = -1;
int l = 0;
frr(i,0,n-k+1){
if(ans<ct[i+k-1]-ct[i+1]){
l = i;
ans = ct[i+k-1] - ct[i+1];
}
}
cout<<ans+1<<" "<<l+1<<endl;
}
}
return 0;
}
C. Nastya and Strange Generator
题意
有一个随机的数字生成器,按照如下生成规则。
-
第 (i) 次操作将数字 (i) 按照下面规则填入;
-
(r_j) 表示位置 (j) 之后的第一个为空的位置;
-
(count_t) 表示位置 (t) 被其他位置选做 (r_j) 的次数,即 (r.count(t));
-
每次只能选取 (count_t) 最大的位置填入 (i) ;
-
如果有多个相同的最大值,则可以从中选取任意一个。
给定一个由 (n) 个不同数字组成的数组,询问能否使用该生成器生成。
解题
这个题也是题面不是很友好,读题面和理解题意用了很长时间。在50分钟的时候过题没想到还能排到1900,说明很多人都被这题面卡住了(绝了
通过举例模拟填充过程发现,填充机制很简单。一旦选取位置 (t) 填充数字 (i) ,那么位置 (t+1) 一定是序列中 (count) 值最大的,所以我们的 (i+1) 必须填充到位置 (t+1) 上,以此类推,直至位置被已被填充或者到达末尾。最后得到的填充序列一定满足以下两个条件:
- 由每小段连续递增子序列组成;
- 前面的连续递增子序列的元素一定大于后面连续子序列的元素。
判断输入序列是否同时满足上面两个条件即可。
#include<bits/stdc++.h>
#define ll long long
#define fr(i,n) for(int i=0;i<n;i++)
#define frs(i,n,flag) for(int i=0;i<n&&flag;i++)
#define frr(i,j,n) for(int i=j;i<n;i++)
#define r_frr(i,j,n) for(int i=n-1;i>=j;i--)
#define frrs(i,j,n,flag) for(int i=j;i<n&&flag;i++)
#define r_frrs(i,j,n,flag) for(int i=n-1;i>=j&&flag;i--)
#define arend(i,n) ((i!=n-1)?" ":"
")
#define memset0(dp) memset(dp,0,sizeof(dp))
#define print_arr(begin,end) for(auto it = begin;it!=end;it++) cout<<*it<<arend(it,end);
#define log_this(name,value) cout<<name<<": "<<value<<endl;
#define e4 10004
#define e5 100005
#define e6 1000006
#define e7 10000007
#define e9 1000000000
#define INF 9999999
using namespace std;
int to_int(string s) {stringstream ss;ss<<s;int a;ss>>a;return a;}
string to_str(double a) {stringstream ss;ss<<a;return ss.str();}
int a[1*e5];
int main(){
cin.tie(0);
//ios::sync_with_stdio(false);
//cout<<setiosflags(ios::fixed)<<setprecision(0);
//freopen("1.out","w",stdout);
int t;
while(cin>>t){
while(t--){
int n;cin>>n;
fr(i,n) cin>>a[i];
int lastw = -1;
int noww = a[n-1];
bool can = true;
r_frr(i,1,n){
if(a[i-1]>a[i]){
if(a[i]<lastw){
can = false;
break;
}
lastw = noww;
noww = a[i-1];
}else{
if(a[i]-a[i-1]>1){
can = false;
break;
}
}
}
if(can) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}
D. Nastya and Scoreboard
题意
有一个由火柴棍拼图组成的序列,询问加上 (k) 根火柴棍能够拼出的最大数字是多少。
解题
首先题面中有两个事情需要注意:
- 输入拼图序列中存在非数字的情况;
- (k) 个火柴可能不能够刚好让所有的拼图变成数字。
贪心+dfs,从大到小搜索可行情况,注意这里要用记搜,不然会超时。
既然记搜可过,看这个数据范围,估计也有dp的解法,等有时间再补上(挖坑+1
#include<bits/stdc++.h>
#define ll long long
#define fr(i,n) for(int i=0;i<n;i++)
#define frs(i,n,flag) for(int i=0;i<n&&flag;i++)
#define frr(i,j,n) for(int i=j;i<n;i++)
#define r_frr(i,j,n) for(int i=n-1;i>=j;i--)
#define frrs(i,j,n,flag) for(int i=j;i<n&&flag;i++)
#define r_frrs(i,j,n,flag) for(int i=n-1;i>=j&&flag;i--)
#define arend(i,n) ((i!=n-1)?" ":"
")
#define memset0(dp) memset(dp,0,sizeof(dp))
#define print_arr(begin,end) for(auto it = begin;it!=end;it++) cout<<*it<<arend(it,end);
#define log_this(name,value) cout<<name<<": "<<value<<endl;
#define e4 10004
#define e5 100005
#define e6 1000006
#define e7 10000007
#define e9 1000000000
#define INF 9999999
using namespace std;
int to_int(string s) {stringstream ss;ss<<s;int a;ss>>a;return a;}
string to_str(double a) {stringstream ss;ss<<a;return ss.str();}
int n,k;
int ans[2005];
int cost[2005][10];
int preCan[2005][2005]; //记录[i+1,n)的元素能否使用j完美填充,-1未访问,0否,1是
string ITB[] = {
"1110111", "0010010", "1011101", "1011011", "0111010", "1101011", "1101111", "1010010", "1111111", "1111011"
};
int Cost(string org,string nto){
int cost = 0;
fr(i,7){
int p = nto[i]-org[i];
if(p<0){
cost = -1;
break;
}else{
cost+=p;
}
}
return cost;
}
bool dfs(int i,int k){
if(i==n&&k==0) return preCan[i][k] = true;
if(k<0 ||(i==n&&k>0)) return preCan[i][k] = false;
r_frr(j,0,10){
if(cost[i][j]!=-1){
//cout<<i<<" "<<j<<" "<<cost[i][j]<<endl;
ans[i] = j;
bool hasf;
int left = k-cost[i][j];
if(preCan[i+1][left]==-1) hasf = dfs(i+1,left);
else hasf = preCan[i+1][left];
if(hasf) return preCan[i][k] = hasf;
}
}
return preCan[i][k] = false;;
}
int main(){
cin.tie(0);
//ios::sync_with_stdio(false);
//cout<<setiosflags(ios::fixed)<<setprecision(0);
while(cin>>n>>k){
string inp;
fr(i,n){
cin>>inp;
fr(j,10) cost[i][j] = Cost(inp,ITB[j]);
}
fr(i,n+1) fr(j,k+1) preCan[i][j] = -1;
bool hasf = dfs(0,k);
if(hasf){
fr(i,n) cout<<ans[i];
cout<<endl;
}else{
cout<<"-1"<<endl;
}
}
return 0;
}