solved(A\B\D)
链接:http://codeforces.com/contest/1036
目录
A. Function Height
水题,略。
B. Diagonal Walking v.2
题目
从原点出发,每次行动可向八个方向走。现在认为 diagonal moves 为斜着走的一步, 给定终点(n,m),要求正好走k步,使得斜着走的步数尽量多,问最多能写着走多少步。
要求:O(1)解法。
题解
首先,如果n>m,那么交换n和m,保证n<m;
然后,我们先走斜线到达(n,n)点,然后问题便转化成了 从(n,n)点正好走(k-n)步,到达(n,m)点。而这两点是在一条直线上的,所以可以通过分奇偶找规律来完成。
(这题卡了很久)
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cmath>
using namespace std;
#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8
#define next next_
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int N = 105;
inline void read(int &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
inline void print(int x) {
if(x<0){ putchar('-'); x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
/*inline void caltime(int tt) {
tt = clock() - tt;
cerr << (double)tt/CLOCKS_PER_SEC << " seconds!" << endl;
}*/
inline void print_matrix(int a[N][N],int n,int m,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}else {
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
}
}
inline void print_line(int *a,int n,bool flag=0) {
if(flag) {
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
}else {
for(int i=0;i<n;i++)
cout<<a[i]<<" ";
}
cout<<endl;
}
ll solve(ll n,ll m,ll k) {
if(n>m) swap(n,m);
if(m>k) return -1;
ll ans = n;
ll x = n,y = n;
ll res = k-n;
ll temp = m-n;
if(res<temp) return -1;
if(temp==0) {
if(res==1) {
ans--;
return ans;
}
if(res&1) ans += res-2;
else ans += res;
return ans;
}
if(temp&1) {
ans += res-1;
}else {
if(res&1) {
ans += res-2;
}else {
ans += res;
}
}
return ans;
}
ll q,n,m,k;
int main()
{
cin>>q;
while(q--) {
scanf("%lld%lld%lld",&n,&m,&k);
ll ans = solve(n,m,k);
cout<<ans<<endl;
}
return 0;
}
D. Vasya and Arrays
题目
给定长度为n的序列a和长度为m的序列b。可以对任意一个序列进行如下操作:用a[l]...a[r]的和去替换掉a[l]...a[r]。
问至少操作多少次,能让a和b相等。否则输出-1.
题解
这题比B题感觉容易不少,A的也很快(最后2分钟a掉了)。
用两个指针分别只向a和b,相应的进行求和,如果suma>sumb,就让j往右移一个,依次类推。
代码
ll n,m,a[maxn],b[maxn];
int main()
{
cin>>n;
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
cin>>m;
for(int i=0;i<m;i++)
scanf("%lld",&b[i]);
int i=0,j=0;
ll sum1 = a[0],sum2 = b[0];
int last = 0;
ll ans = 0;
while(i<n&&j<m) {
// cout<<sum1<<" "<<sum2<<endl;
if(sum1==sum2) {
sum1 = sum2 = 0;
ans += i-last;
last = i+1;
i++;
j++;
sum1 = a[i];
sum2 = b[j];
}
else if(sum1<sum2){
i++;
sum1+=a[i];
}
else if(sum1>sum2){
j++;
sum2 += b[j];
}
}
if(sum1!=sum2) cout<<-1<<endl;
else cout<<n-ans<<endl;
return 0;
}
C. Classy Numbers
题目
给T组询问,每组询问有L和R两个数,要求[L,R]区间中有多少个数字满足条件。
条件:数字中最多含有3个非0数。比如1230,200,340等等,而12345则不符合条件。
L,R<=1e18
题解
由于区间过大,不可能枚举。所以我们可以先把所有符合要求的数求出来(约70万个),然后用二分查找的方法来确定具体个数。
代码
int t;
ll l,r;
vector<ll> e;
void solve(int pos,ll cnt,ll cur) {
if(pos==18) {e.push_back(cur); return;}
solve(pos+1,cnt,cur*10); //当前位为0,继续往后推
if(cnt<3) { //非0数不满3个的情况
for(int i=1;i<=9;i++)
solve(pos+1,cnt+1,cur*10+i);
}
}
int main()
{
solve(0,0,0);
e.push_back(1e18);
cin>>t;
while(t--) {
scanf("%lld%lld",&l,&r);
ll ans = upper_bound(e.begin(),e.end(),r)-lower_bound(e.begin(),e.end(),l); //二分查找,如果前面一个也用lower_bound的话,要分是否正好能找到这个情况来讨论
cout<<ans<<endl;
}
return 0;
}
[点击并拖拽以移动]