期末复习一个月没敲代码了,暑假开始复健hhhh
A. Optimal Path
给出n*m个方格,按照题目所示标号,问从(1,1)到(n,m)所走的路径中,权值最小是多少(权值为路径上所有方格标号数字之和)。
思路:贪心,一定是先按行走再按列走权值最小。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N=1e4+5;
int t,n,m;
ll a[N];
void init(){
for(int i=1;i<=1e4;i++){
a[i]=a[i-1]+i;
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cin>>t;
init();
while(t--){
std::cin>>n>>m;
ll ans1=a[m];
ll ans2=a[n]*m;
std::cout<<ans1+ans2-m<<'\n';
}
return 0;
}
B. Palindromic Numbers
给出一个n位数,求一个相同位的数,使得这两个数相加是回文数。
思路:分类讨论,我们容易想到,9999是回文数,1111也是回文数,那么对于最高位是小于9的数,我们可以令相加所得的回文数为相同位数的9,这样模拟很容易;对于最高位是9的数,我们可以令所得的回文数为高一位的若干个1,模拟减法即可。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N=1e4+5;
int t,n;
std::string x;
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cin>>t;
while(t--){
std::cin>>n>>x;
int len=x.length();
std::stack<int>sta;
bool flag=false;
if(x[0]=='9'){
for(int i=len-1;i>=0;i--){
if(x[i]<='1')
if(!flag)
sta.push(1-(x[i]-'0'));
else{
if(x[i]=='0')
sta.push(0),flag=false;
else{
sta.push(10-(x[i]-'0'));
}
}
else{
if(!flag)
sta.push(11-(x[i]-'0')),flag=true;
else{
sta.push(10-(x[i]-'0'));
}
}
}
while(!sta.empty()){
std::cout<<sta.top();
sta.pop();
}
std::cout<<'\n';
}
else{
std::string s="";
for(int i=0;i<len;i++){
s+=(9-(x[i]-'0')+'0');
}
std::cout<<s<<'\n';
}
}
return 0;
}
os:确实太长时间没练习了,思路慢写代码也慢。
C. Helping the Nature
给出一个数列,问最少经过几次操作使得数列中所有数均为0。操作分为三类:对于标号1~i的数均减一; 对于标号i~n的数均减一; 数列所有的数均加1。
思路:考虑差分。对于三种操作,第一种对应到差分数组就是dif[1]-1,dif[i+1]+1;第二种就是dif[i]-1,dif[n+1]+1;第三种就是dif[1]+1,dif[n+1]-1。所以对于dif数组小于0的,我们可以使用第一种操作,令小于0的变为0,同时对dif[1]进行修改;其他的dif数组中非0的可以使用其他两种操作使其为0,因为a[0]=0,而计算a[n]时与dif[n+1]没有关系,故保证可以这样操作。
#include <bits/stdc++.h>
typedef long long ll;
const int N=2e5+5;
ll t,n;
ll a[N],dif[N];
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cin>>t;
while(t--){
std::cin>>n;
for(int i=1;i<=n;i++){
std::cin>>a[i];
}
for(int i=1;i<=n;i++){
dif[i]=a[i]-a[i-1];
}
ll ans=0;
for(int i=2;i<=n;i++){
if(dif[i]<0) dif[1]+=dif[i],ans-=dif[i],dif[i]=0;
}
for(int i=1;i<=n;i++){
ans+=abs(dif[i]);
}
std::cout<<ans<<'\n';
}
return 0;
}
os:hpggtqllllll!!!
D. River Locks
给出n个空间,每个空间可以盛v[i]的水,每个空间上方有个注水的管道,问最少开几个管道可以使得给出的时间内可以使所有空间都注满水,注意某个空间注满水后剩余的水会流向下一个空间,如图所示。
思路:首先有个前提条件我们应该知道,我们应该尽量开上游的管道,这样可以使得上游的水流到下游而不是直接注入河流造成浪费;这样开x个管道注满所有空间所需的时间是/x,我们容易想到二分答案得到结果。但是注意注满空间是有时间的下限的,即注满前i个空间所需的最短时间是前i个空间之和除以i,所以二分答案之前应该注意判断是否小于下限,若小于则直接输出-1。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N=2e5+5;
ll n,q,x;
ll v[N],f[N];
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cin>>n;
ll max=-1;
for(int i=1;i<=n;i++){
std::cin>>v[i];
f[i]=f[i-1]+v[i];
max=std::max(max,(f[i]+i-1)/i);
}
std::cin>>q;
while(q--){
std::cin>>x;
if(max>x){
std::cout<<-1<<'\n';
continue;
}
ll l=1,r=n;
while(l<r){
ll mid=l+r>>1;
if (x*mid>=f[n]) r=mid;
else l=mid+1;
}
std::cout<<l<<'\n';
}
return 0;
}
太久没打cf头脑都不灵活了,好在有同学这次带飞hhhhh(暑假应该大概可能也许会上青吧)