比赛链接:http://codeforces.com/contest/831
A. Unimodal Array
水题,关键要看清楚题意。
#include <bits/stdc++.h>
using namespace std;
int n, a[110];
int main()
{
while(~scanf("%d",&n)){
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int t = 2;
while(a[t]>a[t-1]) t++;
while(a[t]==a[t-1]) t++;
while(a[t]<a[t-1]) t++;
if(t<=n) puts("NO");
else puts("YES");
}
return 0;
}
B. Keyboard Layouts
水题,用map映射一下就可以了。
#include <bits/stdc++.h>
using namespace std;
map<char,char>mp;
string s1,s2,s3;
int main(){
cin>>s1>>s2>>s3;
for(int i=0; i<26; i++){
mp[s1[i]]=s2[i];
mp[char(s1[i]-32)]=char(s2[i]-32);
}
for(int i=0; i<s3.size(); i++){
if(isdigit(s3[i])) printf("%c", s3[i]);
else printf("%c", mp[s3[i]]);
}
printf("\n");
}
C. Jury Marks
题意:给你n个评委打分的情况,和其中k次分数,问你初始分数的可能数。
解法:首先出力出打分的前缀和,能知道到第i个人评分后距离初试分数的差值然后排序,去重。之后再统计次数,如果次数等于n说明这个分数就可以。
#include <bits/stdc++.h>
using namespace std;
unordered_map<int,int>mp;
int a[2010], b[2010] , sum[2010];
vector <int> v[2010];
int main()
{
int k, n, ans;
while(~scanf("%d%d",&k,&n)){
mp.clear();
memset(sum, 0, sizeof(sum));
ans = 0;
for(int i=1; i<=k; i++){
scanf("%d", &a[i]);
sum[i] = sum[i-1] + a[i];
}
for(int i=1; i<=n; i++){
scanf("%d", &b[i]);
}
for(int i=1; i<=n; i++){
for(int j=1; j<=k; j++){
int t = b[i] - sum[j];
v[i].push_back(t);
}
sort(v[i].begin(),v[i].end());
v[i].erase(unique(v[i].begin(), v[i].end()), v[i].end());
}
for(int i=1; i<=n; i++){
for(int j=0; j<v[i].size(); j++){
mp[v[i][j]]++;
}
}
for(unordered_map<int,int>::iterator it = mp.begin(); it!=mp.end(); it++){
if((it->second)>=n){
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}
D. Office Keys
题意:有n个人,m个keys,目的地p,每个人要拿一个keys到达p,没走1m花费1个单位时间,问所有人到达p的最小时间
解法1:首先考虑这是在直线上,从最左边的人开始枚举,那么为了方便其他人,他所拿的keys一定是尽可能靠左的,所以二分答案 check就行了
解法2:DP。dp[i][j]表示前i个人利用前j把钥匙都走到p的最小时间,直接O(n*k)枚举转移。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2010;
int n, k, p, a[maxn], b[maxn];
long long dp[maxn][maxn];
//dp[i][j]表示前i个人利用前j把钥匙都走到p的最小时间
int main()
{
while(~scanf("%d %d %d", &n, &k, &p))
{
for(int i=1; i<=n; i++) scanf("%d", &a[i]);
for(int i=1; i<=k; i++) scanf("%d", &b[i]);
sort(a+1,a+n+1);
sort(b+1,b+k+1);
memset(dp, 0x3f, sizeof(dp));
for(int i=0; i<=k; i++) dp[0][i] = 0;
for(int i=1; i<=n; i++){
for(int j=1; j<=k; j++){
long long dis = abs(a[i]-b[j])+abs(b[j]-p);
dp[i][j] = dp[i][j-1];
dp[i][j] = min(dp[i][j], max(dp[i-1][j-1],dis));
}
}
printf("%lld\n", dp[n][k]);
}
return 0;
}
E. Cards Sorting
题意:有n张卡片,成一个队列,每次操作如果队头是队列中最小的就拿出去,否则放到队尾。问等队列为空 操作了多少次?
解法:
其实就是个模拟。
但是直接模拟复杂度是O(n2)的 显然不可取
然后考虑如何维护。
首先由于有删除点,首先想到SPLAY维护,将该删除的删除,或者放到意义上的最后。
每次找当前意义上对头后面的最近的最小值
复杂度大概是O(nlognlogn) 而且实现起来有一定难度,
然后想每一次删除相当于存在,或者不存在, 想到用BIT维护 即可求意义上的两次删点的操作次数。
找最小值,看到1e6的范围想到桶排,然后同样大小的 要记录位置,所以开vector数组即可
维护一个意义上队头,然后二分找那个位置最近。不断维护即可
复杂度是O(nlogn)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 100010;
namespace BIT{
int c[maxn];
void init(){
memset(c, 0, sizeof(c));
}
int lowbit(int x){
return x&-x;
}
void update(int x, int val){
for(;x<maxn;x+=lowbit(x)) c[x] += val;
}
int query(int x){
int ret = 0;
while(x>0){
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
int query(int l, int r){
if(l>r) return query(r)+query(maxn) - query(l-1);
else return query(r)-query(l-1);
}
};
using namespace BIT;
vector <int> pos[maxn];
int n, x, nowpos, nxtpos;
LL ans;
int main(){
while(~scanf("%d", &n)){
init();
for(int i=0; i<maxn; i++) pos[i].clear();
for(int i=1; i<=n; i++){
scanf("%d", &x);
pos[x].push_back(i);
update(i,1);
}
nowpos = ans = 0;
for(int i=1; i<maxn; i++){
if(pos[i].size()){
nxtpos = lower_bound(pos[i].begin(), pos[i].end(), nowpos) - pos[i].begin();
if(nxtpos == pos[i].size()) nxtpos = 0;
for(int j=0; j<pos[i].size(); j++){
ans += query(nowpos, pos[i][nxtpos]);
update(pos[i][nxtpos],-1);
nowpos = pos[i][nxtpos];
nxtpos++;
if(nxtpos == pos[i].size()) nxtpos = 0;
}
}
}
printf("%lld\n", ans);
}
return 0;
}
F. Bamboo Partition
题意:有n个植物,最开始均为0米。每天长1米。可以认为修剪,且修建后植物不生长。每隔d天需要人去修剪照看。问你在剪下去的长度和小于k的情况下 d最大为多少,看了这个题解:http://blog.csdn.net/qq_33184171/article/details/75138225
核心式子就是 d<=(k+∑ni=1a[i])∑ni=1ceil(a[i]d)
那么直接枚举 (k+∑ni=1a[i]) 的约数就可以可以了。
代码1:按照上面题解的方法维护
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n, k, a[110];
int main(){
while(~scanf("%lld%lld", &n,&k)){
LL s = 0, ans = -1;
for(int i=1; i<=n; i++){
scanf("%lld", &a[i]);
s += a[i];
}
sort(a+1, a+n+1);
for(int i=1; i<=n; i++) a[i]--;
LL d2 = (s+k)/n;
if(d2 > a[n]) ans = max(ans, d2);
for(LL d=1, r; d<=a[n]; d=r+1){
r = a[n];
LL s1 = 0;
for(int j=1; j<=n; j++){
s1 += a[j]/d+1;
if(a[j]/d) r = min(r, a[j]/(a[j]/d));
}
LL d1 = min(r, (s+k)/s1);
if(d1 >= d) ans = max(ans, d1);
}
printf("%lld\n", ans);
}
return 0;
}
代码2:按照第二种理解的方法
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL ans, tot, n;
LL a[105];
void update(LL d)
{
LL sum = 0;
for(int i = 1; i <= n; i++)
sum += (a[i] - 1) / d + 1;
if(sum * d <= tot)
ans = max(ans, d);
}
int main()
{
LL k;
scanf("%lld %lld", &n, &k);
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
tot += a[i];
}
tot += k;
for(LL i = 1; i * i <= tot; i++)
{
update(i);
update(tot / i);
}
printf("%lld\n", ans);
return 0;
}