@wsndy-xx
2018-06-25T09:04:12.000000Z
字数 7436
阅读 1108
题解
题意:给定一个十进制正整数N,写下从1开始,到N的所有正数,计算出其中出现所有1的个数
思路:分块打表或者分类讨论
#include<stdio.h>
long long int Count(long long int n){
//1的个数
long long int count = 0;
//当前位
long long int Factor = 1;
//低位数字
long long int LowerNum = 0;
//当前位数字
long long int CurrNum = 0;
//高位数字
long long int HigherNum = 0;
if(n <= 0){
return 0;
}
while(n / Factor != 0){
//低位数字
LowerNum = n - (n / Factor) * Factor;
//当前位数字
CurrNum = (n / Factor) % 10;
//高位数字
HigherNum = n / (Factor * 10);
//如果为0,出现1的次数由高位决定
if(CurrNum == 0){
//等于高位数字 * 当前位数
count += HigherNum * Factor;
}
//如果为1,出现1的次数由高位和低位决定
else if(CurrNum == 1){
//高位数字 * 当前位数 + 低位数字 + 1
count += HigherNum * Factor + LowerNum + 1;
}
//如果大于1,出现1的次数由高位决定
else{
//(高位数字+1)* 当前位数
count += (HigherNum + 1) * Factor;
}
//前移一位
Factor *= 10;
}
return count;
}
int main(){
long long int a;
while(scanf("%lld",&a) != EOF){
printf("%lld\n",Count(a));
}
return 0;
}
题意:有编号1-n的n个格子,机器人从1号格子顺序向后走,一直走到n号格子,并需要从n号格子走出去。机器人有一个初始能量,每个格子对应一个整数A[i],表示这个格子的能量值。如果A[i] > 0,机器人走到这个格子能够获取A[i]个能量,如果A[i] < 0,走到这个格子需要消耗相应的能量,如果机器人的能量 < 0,就无法继续前进了。问机器人最少需要有多少初始能量,才能完成整个旅程。
思路:判断最小前缀和
#include <iostream>
#include <cstdio>
#include <algorithm>
#define LL long long
const int N = 50010;
LL A[N], Minn;
int n;
int main() {
std:: cin >> n;
for(int i = 1; i <= n; i ++) std:: cin >> A[i];
Minn = A[1];
for(int i = 2; i <= n; i ++) {
A[i] += A[i - 1];
Minn = std:: min(A[i], Minn);
}
if(Minn >= 0) std:: cout << 0;
else std:: cout << -Minn;
return 0;
}
题意:有一口井,井的高度为N,每隔1个单位它的宽度有变化。现在从井口往下面扔圆盘,如果圆盘的宽度大于井在某个高度的宽度,则圆盘被卡住(恰好等于的话会下去)。
盘子有几种命运:1、掉到井底。2、被卡住。3、落到别的盘子上方。
盘子的高度也是单位高度。给定井的宽度和每个盘子的宽度,求最终落到井内的盘子数量。
思路:前缀最小值优化,对每一个盘子找到最优的位置
#include <iostream>
#include <cstdio>
#include <algorithm>
const int N = 50010;
int A[N], B[N], At, Bt;
int Minn[N]; //前缀最小值
int main() {
std:: cin >> At >> Bt;
for(int i = 1; i <= At; i ++) std:: cin >> A[i];
for(int i = 1; i <= Bt; i ++) std:: cin >> B[i];
Minn[1] = A[1];
for(int i = 2; i <= At; i ++) Minn[i] = std:: min(Minn[i - 1], A[i]);
int down = At, i;
for(i = 1; i <= Bt && down > 0; i ++) {
if(Minn[down] >= B[i]) {down --; continue;}
while(Minn[down] < B[i] && down) down --;
if(down == 0) break;
down --;
}
std:: cout << i - 1;
return 0;
}
题意: n个人,已知每个人体重。独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人。显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟?
思路: 排序后贪心
#include <iostream>
#include <cstdio>
#include <algorithm>
const int N = 10010;
int A[N], n, m;
int main() {
std:: cin >> n >> m;
for(int i = 1; i <= n; i ++) std:: cin >> A[i];
std:: sort(A + 1, A + n + 1);
int l = 1, r = n, js = 0, Answer = 0;
while(js != n) {
if(A[l] + A[r] <= m) l ++, r --, js += 2, Answer ++;
else r --, js ++, Answer ++;
if(l == r) {Answer ++; break;}
}
std:: cout << Answer;
return 0;
}
题意:平面上有N个点,任意2个点确定一条直线,求出所有这些直线中,斜率最大的那条直线所通过的两个点。
(点的编号为1-N,如果有多条直线斜率相等,则输出所有结果,按照点的X轴坐标排序,正序输出。数据中所有点的X轴坐标均不相等,且点坐标为随机。)
思路: 暴力判断
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
const int N = 10010;
const double eps = 1e-10;
struct Node {int x, y;} Point[N];
int n, Ans_js;
Node Ans[N];
inline double Get_k(int a, int b) {
return (double)(Point[a].y - Point[b].y) / (double)(Point[a].x - Point[b].x);
}
int main() {
std:: cin >> n;
for(int i = 1; i <= n; i ++) std:: cin >> Point[i].x >> Point[i].y;
double Max_k = 0;
for(int i = 1; i <= n; i ++)
for(int j = i + 1; j <= n; j ++) {
double Now_k = Get_k(i, j);
if(Now_k > Max_k) {
Max_k = Now_k; Ans_js = 0;
if(Point[i].x < Point[j].x) Ans[++ Ans_js].x = i, Ans[Ans_js].y = j;
else Ans[++ Ans_js].x = j, Ans[Ans_js].y = i;
} else if(Now_k == Max_k) {
if(Point[i].x < Point[j].x) Ans[++ Ans_js].x = i, Ans[Ans_js].y = j;
else Ans[++ Ans_js].x = j, Ans[Ans_js].y = i;
}
}
for(int i = 1; i <= Ans_js; i ++) std:: cout << Ans[i].x << " " << Ans[i].y << "\n";
return 0;
}
题意:现有的统计工具只能统计某一个窗口中,用户的满意程度的均值。夹克老爷想让你为统计工具添加一个新feature,即在统计均值的同时,计算窗口中满意程度的标准差和中位数(均值需要向下取整)。
思路:线段树维护
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
using namespace std;
#define LL long long
double he[2];
int shu;
struct node{int l,r,shu;}PP[300];
void creat(int l,int r,int x)
{
PP[x].l=l;PP[x].r=r;
PP[x].shu=0;
if (l==r) return ;
int m=(l+r)>>1;
creat(l,m,x*2);
creat(m+1,r,x*2+1);
}
void add(int wei,int x)
{
PP[x].shu++;
if (PP[x].l==PP[x].r) return ;
int m=(PP[x].l+PP[x].r)>>1;
if (wei>m) add(wei,x*2+1);
else add(wei,x*2);
}
void jian(int wei,int x)
{
PP[x].shu--;
if (PP[x].l==PP[x].r) return ;
int m=(PP[x].l+PP[x].r)>>1;
if (wei>m) jian(wei,x*2+1);
else jian(wei,x*2);
}
int query(int ll,int x)
{
if (PP[x].l==PP[x].r)
return PP[x].l;
else if (PP[x*2].shu<ll)
query(ll-PP[x*2].shu,x*2+1);
else
query(ll,x*2);
}
int main()
{
queue<int> que;
int n,k;
scanf("%d%d",&n,&k);
int s=0,a,b;
shu=0;
creat(0,100,1);
while (n--)
{
scanf("%d",&a);
switch(a)
{
case 1:
if (shu==k)
{
b=que.front();
que.pop();
he[0]-=b;
he[1]-=b*b;
jian(b,1);
}
else shu++;
scanf("%d",&b);
que.push(b);
he[0]+=b;he[1]+=b*b;
add(b,1);
break;
case 2:
printf("%d.00\n",((int)he[0])/shu);
break;
case 3:
printf("%.2lf\n",he[1]/shu-(he[0]/shu)*(he[0]/shu));
break;
case 4:
if (shu%2==0)
{
a=query(shu/2,1);
b=query(shu/2+1,1);
printf("%.2lf\n",(a+b)/2.0);
}
else
{
b=query(shu/2+1,1);
printf("%.2lf\n",(double)b);
}
break;
}
}
return 0;
}
题意:有N只兔子,每只有一个血量B[i],需要用箭杀死免子。有M种不同类型的箭可以选择,每种箭对兔子的伤害值分别为D[i],价格为P[i](1 <= i <= M)。假设每种箭只能使用一次,每只免子也只能被射一次,计算要消灭地图上的所有兔子最少需要多少Q币。如不能杀死所有兔子,请输出No Solution。
特别说明:1、当箭的伤害值大于等于兔子的血量时,能将兔子杀死;2、血量B[i],箭的伤害值D[i],箭的价格P[i],均小于等于100000。
思路:对血量贪心找到最合适的剑,优先队列优化
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N = 50010;
int B[N];
struct Node {
int hit, money;
}A[N];
int n, m;
bool operator <(Node a, Node b) {return a.money > b.money;}
bool cmp_1(int a, int b) {return a > b;}
bool cmp_2(Node a, Node b) {return a.hit > b.hit;}
priority_queue <Node> Q;
int main() {
cin >> n >> m;
if(n > m) {cout << "No Solution"; return 0;}
for(int i = 1; i <= n; i ++) cin >> B[i];
for(int i = 1; i <= m; i ++) cin >> A[i].hit >> A[i].money;
std:: sort(B + 1, B + n + 1, cmp_1);
std:: sort(A + 1, A + m + 1, cmp_2);
int Answer = 0;
for(int i = 1, j = 1; i <= n; i ++) { // 对于每一只兔子寻找合适的炮
for(; j <= m; j ++)
if(A[j].hit >= B[i]) Q.push(A[j]);
else break;
if(!Q.empty()) {
Node topp = Q.top();
Q.pop();
Answer += topp.money;
} else {
cout << "No Solution"; return 0;
}
}
std:: cout << Answer;
return 0;
}
题意:一个长度为M的正整数数组A,表示从左向右的地形高度。测试一种加农炮,炮弹平行于地面从左向右飞行,高度为H,如果某处地形的高度大于等于炮弹飞行的高度H(A[i] >= H),炮弹会被挡住并落在i - 1处,则A[i - 1] + 1。如果H <= A[0],则这个炮弹无效,如果H > 所有的A[i],这个炮弹也无效。现在给定N个整数的数组B代表炮弹高度,计算出最后地形的样子。
例如:地形高度A = {1, 2, 0, 4, 3, 2, 1, 5, 7}, 炮弹高度B = {2, 8, 0, 7, 6, 5, 3, 4, 5, 6, 5},最终得到的地形高度为:{2, 2, 2, 4, 3, 3, 5, 6, 7}。
思路:对于每一个高度,预处理出应该落在哪里,对于每一发炮弹下落后影响的高度为 级别的,可以判断后调整,预处理时可以前缀最大值优化。
#include <bits/stdc++.h>
const int N = 50010;
int n, m;
int A[N], B[N];
int hight[N * 22], Max_hight;
int Maxn[N];
int Answer[N];
int main() {
std:: cin >> n >> m;
for(int i = 1; i <= n; i ++) std:: cin >> A[i];
for(int i = 1; i <= m; i ++) std:: cin >> B[i];
for(int i = 1; i <= m; i ++) Max_hight = std:: max(Max_hight, B[i]);
for(int i = 1; i <= n; i ++) Maxn[i] = std:: max(Maxn[i - 1], A[i]); // 前缀最大值
for(int i = 1; i <= n; i ++)
if(Maxn[i] != Maxn[i - 1])
for(int j = Maxn[i - 1] + 1; j <= Maxn[i]; j ++)
hight[j] = i;
for(int j = Maxn[n] + 1; j <= Max_hight; j ++) hight[j] = n + 2;
for(int i = 1; i <= m; i ++) {
int H = hight[B[i]];
if(H > n || !H) continue ;
A[H - 1] ++;
hight[A[H - 1]] = std:: min(hight[A[H - 1]], H - 1);
hight[A[H - 1] - 1] = std:: min(hight[A[H - 1] - 1], H - 1);
}
for(int i = 1; i <= n; i ++) std:: cout << A[i] << "\n";
return 0;
}
题意:有N行M列的正方形盒子。每个盒子有三种状态0, -1, +1。球从盒子上边或左边进入盒子,从下边或右边离开盒子。规则:
如果盒子的模式是-1,则进入它的球从下面出去。(方向变为向下)
如果盒子的模式是+1,则进入它的球从右面出去。 (反向变为向右)
如果盒子的模式是0, 则进入它的球方向不变。从上面进入的,从下面出去,从左面进入的,从右面出去。
思路:每个格子在经过后会变为相反数,经过一个格子的球的数目可以由该格子上方的格子向下走的数量 + 该格子左边的格子向右走的数量相加得到,该格子向右或向下走的数量又可以由该格子的初始状态决定
因此就可以完美递推啦
#include <bits/stdc++.h>
const int N = 1e3 + 10;
int A[N][N];
int n, m;
long long k, Sum[N][N][2];
inline long long read() {
long long x; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}
int main() {
std:: cin >> m >> n >> k;
for(int i = 1; i <= n; i ++) for(int j = 1; j <= m; j ++) std:: cin >> A[i][j];
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
if(i == 1 && j == 1) {
if(A[1][1] == 1) Sum[1][1][1] = (k + 1) >> 1, Sum[1][1][0] = k >> 1;
else if(A[1][1] == -1) Sum[1][1][0] = (k + 1) >> 1, Sum[1][1][1] = k >> 1;
else Sum[1][1][0] = k;
} else {
long long tmp = Sum[i - 1][j][0] + Sum[i][j - 1][1];
if(!A[i][j]) Sum[i][j][0] = Sum[i - 1][j][0], Sum[i][j][1] = Sum[i][j - 1][1];
else if(A[i][j] == 1) Sum[i][j][1] = (tmp + 1) >> 1, Sum[i][j][0] = tmp >> 1;
else Sum[i][j][0] = (tmp + 1) >> 1, Sum[i][j][1] = tmp >> 1;
}
}
}
std:: cout << Sum[n][m][0];
return 0;
}
/*
3 2 4
-1 0 -1
1 0 0
*/