A. Unimodal Array 题目链接
题意:
①先严格递增
②相等
③严格递减
只要一个序列的大小变化的顺序满足以上即为 unimodal
现在给定一个序列,询问是否为 unimodal
思路:
分别定义三种情况为0,1,2
然后判断是否出现了倒序即可
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int A[105];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&A[i]);
}int k = 0;
for(int i=1;i<n;i++){
int t ;
if(A[i]>A[i-1]){
t = 0;
}else if(A[i]==A[i-1]){
t = 1;
}else {
t = 2;
}if(k>t){
printf("NO\n");
return 0;
}k = t;
}printf("YES\n");
return 0;
}
B. Keyboard Layouts 题目链接
题意:
一个键盘上26个字母分别对应了新的26个字母,问现在按下一个对应的字母序列问最后得到的结果
思路:
用map映射一下即可,注意大小写都要映射,不是字母的照常输出
代码:
#include<bits/stdc++.h>
char s1[100];
char s2[100];
char str[1005];
using namespace std;
map<char,char>M;
int main(){
scanf("%s%s%s",s1,s2,str);
for(int i=0;i<26;i++){
M[s1[i]] = s2[i];
M['A'+s1[i]-'a'] = 'A' + s2[i] - 'a' ;
}for(int i=0;str[i];i++)
printf("%c",isalpha(str[i])?M[str[i]]:str[i]);
return 0;
}
这个因为出了一个平时没有注意的BUG,所以单独写了一篇博客
D. Office Keys 题目链接
题意:
有n个人,k把钥匙,办公室的位置在p,给出每个人的位置,每把钥匙的位置
现在每个人要拿一把钥匙才能进入办公室,每把钥匙只能被一个人用
问所有人都进入办公室的最少要花费的时间
思路:
因为两个人交叉拿钥匙一定不是最优的情况
所以先对每个人的位置进行排序,对每把钥匙的位置进行排序
定义状态dp[ i ][ j ]:前 i 把钥匙让前 j 个人用进入办公室的最少要花费的时间
那么 dp[ i ][ j ] = min( dp[ i-1 ] [ j ] , max( dp[ i-1 ][ j-1 ] , cost ( i , j ) ) )
cost ( i , j ) 为 第 j 个人拿第 i 把钥匙进入办公室花费的时间
复杂度O(n*k + nlog(n) + klog(k) )
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,p;
int A[1005];
int B[2005];
long long dp[2005][1005];
long long cost(int i,int j){
return abs(0LL+A[j]-B[i])+abs(0LL+p-B[i]);
}
int main()
{
memset(dp,0x3f,sizeof(dp));
scanf("%d%d%d",&n,&k,&p);
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
}sort(A+1,A+1+n);
for(int j=1;j<=k;j++){
scanf("%d",&B[j]);
dp[j][0] = 0;
}sort(B+1,B+1+k);
dp[0][0] = 0;
for(int i=1;i<=k;i++){
for(int j=1;j<=min(i,n);j++){
dp[i][j] = min(dp[i-1][j],max(dp[i-1][j-1],cost(i,j)));
}
}printf("%I64d\n",dp[k][n]);
return 0;
}
E. Cards Sorting 题目链接
题意:
一堆牌以队列的形式放在桌子上,你每次要判断队头是牌是不是最小的牌
如果是,则拿出来,如果不是,则放到队尾
询问把所有牌拿完的操作次数
思路:
很直白的线段树区间查询+单点修改模板题
先用随便一种操作处理出路径,每次查询路径上没有被拿出的牌的数目,然后把路径上最小的牌的位置的权值更新
复杂度O( nlog(n) )
代码:
#include<bits/stdc++.h>
#define lson (now<<1)
#define rson lson+1
#define Lson lson,l,(l+r)>>1
#define Rson rson,((l+r)>>1)+1,r
const int MAXN = 1e5+10;
using namespace std;
int n;
int A[MAXN];
int pos[MAXN];
bool cmp(int a,int b){
if(A[a]!=A[b])return A[a]<A[b];
return a<b;
}
struct node{
int val;
}seg[MAXN<<2];
void build(int now,int l,int r){
if(l==r){
seg[now].val = 1;
}else {
build(Rson);
build(Lson);
seg[now].val = seg[lson].val + seg[rson].val ;
}
}
void update(int now,int l,int r,int pos){
if(l==r&&l==pos){
seg[now].val=0;
}else if(l>pos||r<pos)return ;
else if(l<=pos&&r>=pos){
update(Lson,pos);
update(Rson,pos);
seg[now].val --;
}
}
int query(int now,int l,int r,int s,int e){
if(l>e||r<s)return 0;
if(l>=s&&r<=e)return seg[now].val;
return query(Lson,s,e) + query(Rson,s,e);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
pos[i] = i;
}sort(pos+1,pos+1+n,cmp);
long long ans = 0;
build(1,1,n);
int index = 0 , now = 1;
while(index<n){
int last = index+1 , mi = pos[last] , mx = pos[last];
while(last<n&&A[pos[last]]==A[pos[last+1]]){
int p = pos[++last];
mx = p;
if(p<now)mi = p;
}
if(mi<now){
ans += query(1,1,n,now,n) + query(1,1,n,1,mi);
now = mi;
}else {
ans += query(1,1,n,now,mx) ;
now = mx;
}
while( ++index <= last )update(1,1,n,pos[index]);
index--;
}printf("%I64d\n",ans);
return 0;
}
F. Bamboo Partition 题目链接
题意:
有n个竹子,竹子每天长1m,每个竹子都有一个你认为的临界高度ai
你每d天去看一次竹子,如果有竹子的高度超过了对应的临界高度,你就会把它砍断(不会再长高),然后把高于ai的部分收集起来
现在求一个最大的d,满足最后收集到的竹子长度小于等于给定的k
思路:
若每d天去看一次竹子,最后收集到的长度为:
要求最大d,使得这个式子最后的值小于等于k,那么整理一下得:
令右式等于sum,两边同时除以d,得:
于是我们发现若两个数d1,d2(d1<=d2)满足
因为d1的左式大于等于d2的左式,所以若d1的不等式为真,那么d2的不等式一定为真
于是我们可以用分块加速的方法check所有块里最大的d,复杂度为O( n * sqrt( k + sum(ai) ) )刚好满足题意
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int A[105];
long long mx ;
bool check(long long x){
long long res = 0;
for(int i=0;i<n;i++){
long long k = (A[i]-1)/x;
res += (k*x+x-A[i]);
}
return res <= mx;
}
int main()
{
scanf("%d%I64d",&n,&mx);
long long s = 1 , e = mx;
for(int i=0;i<n;i++){
scanf("%d",&A[i]);
e += A[i];
}long long ans = 0;
for(long long s = 1, last ;s<=e ;s=last+1){
last = e / ( e / s );
if(check(last))ans = last;
}printf("%I64d\n",ans);
return 0;
}