模拟
ZZNUOJ 2117 我已经在路上了(大力分类讨论)
题意: 给你一个简单函数,只包括几个原函数: y = C , y = x , y = x n , y = s i n x , y = c o s x , y = l n x , y = l o g a ( x ) , y = e x , y=C,y=x,y=x^n,y=sinx,y=cosx,y=lnx,y=log_a(x),y=e^x, y=C,y=x,y=xn,y=sinx,y=cosx,y=lnx,y=loga(x),y=ex,
要求输出求导函数
思路: 八大类,每一类基本都有一两个特判,大力出奇迹!
注意爆 i n t int int ,要开 l o n g l o n g long \ long long long 。
代码: (耗时: 58 m i n 58 min 58min)
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#define fi first
#define se second
//#include<stdlib.h>
//#include <time.h>
//srand((unsigned)time(NULL));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
using namespace std;
#define int ll
bool isok(char c) {
return c >= '0' && c <= '9';
}
signed main() {
string s;
while (cin >> s) {
if (s.find("x") != -1) {
if (s.find("sin") != -1) {
int p = s.find("sin");
int num[2] = {0};
for (int i = 2; i < p; i++) {
if (isok(s[i]))
num[0] = num[0] * 10 + s[i] - '0';
}
for (int i = p + 3; i < (int)s.size(); i++) {
if (s[i] == 'x') break;
if (isok(s[i]))
num[1] = num[1] * 10 + s[i] - '0';
}
if (num[0] == 0) num[0] = 1;
if (num[1] == 0) num[1] = 1;
int c1 = num[0] * num[1];
if (c1 > 1) printf("%lld", c1);
printf("cos");
if (num[1] > 1) printf("%lld", num[1]);
printf("x\n");
}
else if (s.find("cos") != -1) {
int p = s.find("cos");
int num[2] = {0};
for (int i = 2; i < p; i++) {
if (isok(s[i]))
num[0] = num[0] * 10 + s[i] - '0';
}
for (int i = p + 3; i < (int)s.size(); i++) {
if (s[i] == 'x') break;
if (isok(s[i]))
num[1] = num[1] * 10 + s[i] - '0';
}
for (int i = 0; i < 2; i++)
if (num[i] == 0) num[i] = 1;
int c1 = -1 * num[0] * num[1];
if (c1 == -1) printf("-");
else printf("%lld", c1);
printf("sin");
if (num[1] > 1) printf("%lld", num[1]);
printf("x\n");
}
else if (s.find("ln") != -1) {
int p = s.find("ln");
int num = 0;
for (int i = 2; i < p; i++) {
if (isok(s[i]))
num = num * 10 + s[i] - '0';
}
if (num == 0) num = 1;
printf("%lld/x\n", num);
}
else if (s.find("log") != -1) {
int p = s.find("log");
int num[2] = {0};
for (int i = 2; i < p; i++)
if (isok(s[i])) num[0] = num[0] * 10 + s[i] - '0';
for (int i = p + 3; i < (int)s.size(); i++) {
if (s[i] == 'x' || s[i] == '(') break;
if (isok(s[i])) num[1] = num[1] * 10 + s[i] - '0';
}
for (int i = 0; i < 2; i++)
if (num[i] == 0) num[i] = 1;
printf("%lld", num[0]);
printf("/ln%lld/x\n", num[1]);
}
else if (s.find("^") != -1) {
int p = s.find("^");
if (s[p - 1] == 'x') {
int num = 0;
int n = 0;
for (int i = 2; i < p - 1; i++) {
if (isok(s[i])) num = num * 10 + s[i] - '0';
}
for (int i = p + 1; i < (int)s.size(); i++) {
if (isok(s[i])) {
n = n * 10 + s[i] - '0';
}
}
if (num == 0) num = 1;
if (n == 1) {
printf("%lld\n", num);
}
else {
int c = num * n;
printf("%lld", c);
if (n == 2) printf("x\n");
else printf("x^%lld\n", n - 1);
}
}
else if (s[p - 1] == 'e') {
int num[2] = {0};
for (int i = 2; i < p - 1; i++)
if (isok(s[i])) num[0] = num[0] * 10 + s[i] - '0';
for (int i = p + 1; i < (int)s.size(); i++) {
if (s[i] == 'x') break;
if (isok(s[i])) num[1] = num[1] * 10 + s[i] - '0';
}
for (int i = 0; i < 2; i++)
if (num[i] == 0) num[i] = 1;
int c = num[0] * num[1];
if (c != 1) printf("%lld", c);
printf("e^");
if (num[1] > 1) printf("%lld", num[1]);
printf("x\n");
}
}
else {
int p = s.find("x");
int c = 0;
for (int i = 2; i < p; i++)
if (isok(s[i])) c = c * 10 + s[i] - '0';
if (c == 0) c = 1;
printf("%lld\n", c);
}
}
else {
printf("0\n");
}
}
return 0;
}
luogu P1686 挑战(模拟(提交次数1)
题意: 给定一串表示方向的字符串,都是平行于 x x x 或 y y y 轴的。现在要求你找到一条最短的捷径:长度最短 > 起点小 > 终点大( 捷径必须是水平或者竖直的)
思路: 根据题意,不难看出,要求的其实是不相邻的点之间的最短水平或者竖直距离,先把 ( 0 , 0 ) (0,0) (0,0) 作为起点,然后将路径用二维坐标把路线表示出来,先按 x x x 坐标排序,然后根据 y y y 坐标相同的点对来更新答案,然后再按 y y y 排序,同理更新答案。
代码: (耗时: 30 m i n 30min 30min)
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
//#include<cmath>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#define fi first
#define se second
//#include<stdlib.h>
//#include <time.h>
//srand((unsigned)time(NULL));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
using namespace std;
const int N = 1e6 + 10;
int n;
struct Point{
int x, y;
int id;
Point() {}
Point(int _x, int _y) {
x = _x; y = _y;
}
}p[N];
char s[N];
bool cmpx(Point a, Point b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
bool cmpy(Point a, Point b) {
return a.y < b.y || (a.y == b.y && a.x < b.x);
}
int ans;
int st, ed;
char to;
void judgex() { //按x排序后,找y
for (int i = 1; i <= n; i++) {
if (p[i].x == p[i - 1].x) {
if (abs(p[i].id - p[i - 1].id) == 1) continue;
int len = abs(p[i].y - p[i - 1].y);
int a = p[i - 1].id, b = p[i].id;
char t = 'N';
if (a > b) {
swap(a, b);
t = 'S';
}
if (len < ans) {
ans = len;
st = a; ed = b;
to = t;
}
else if (len == ans) {
if (st > a) {
ans = len;
st = a; ed = b;
to = t;
}
else if (st == a) {
if (ed < b) {
ans = len;
st = a; ed = b;
to = t;
}
}
}
}
}
}
void judgey() {
for (int i = 1; i <= n; i++) {
if (p[i - 1].y == p[i].y) {
if (abs(p[i - 1].id - p[i].id) == 1) continue;
int len = abs(p[i].x - p[i - 1].x);
int a = p[i - 1].id, b = p[i].id;
char t = 'E';
if (a > b) {
swap(a, b);
t = 'W';
}
if (len < ans) {
ans = len;
st = a; ed = b;
to = t;
}
else if (len == ans) {
if (a < st) {
ans = len;
st = a; ed = b;
to = t;
}
else if (a == st) {
if (ed < b) {
ans = len;
st = a; ed = b;
to = t;
}
}
}
}
}
}
int main() {
scanf("%d", &n);
p[0] = Point(0, 0);
p[0].id = 0;
scanf("%s", s + 1);
for (int i = 1; i <= n; i++) {
if (s[i] == 'N') p[i] = Point(p[i - 1].x, p[i - 1].y + 1);
else if (s[i] == 'E') p[i] = Point(p[i - 1].x + 1, p[i - 1].y);
else if (s[i] == 'S') p[i] = Point(p[i - 1].x, p[i - 1].y - 1);
else p[i] = Point(p[i - 1].x - 1, p[i - 1].y);
p[i].id = i;
}
ans = INF;
st = -1; ed = -1;
sort(p, p + n + 1, cmpx);
judgex();
// printf("%d %d %d %c\n", ans, st, ed, to);
sort(p, p + n + 1, cmpy);
judgey();
printf("%d %d %d %c\n", ans, st, ed, to);
return 0;
}
luogu P3161 模拟工厂(状压枚举+贪心+模拟)
题意: 现在有 n n n 个订单,每个订单要求在规定时间 t t t 时完成 g g g 件商品,并能获得 m m m 的收入。每一时刻可能有多个订单,但不一定都要完成,初始时(0时刻),你的生产力是 1 1 1 ,每一时刻,你可以选择生产力 + 1 +1 +1 或者生产产品(生产的产品数是你当前的生产力大小)。 求最大收入。
思路: 因为 n < = 15 n <= 15 n<=15 很小,直接枚举状态然后判断是否可行,接下来就是怎么贪的问题。
先讲一下我之前错误的两次贪心:首先都先对所有任务按时间排序,并状态枚举,对于每一种状态:
第一次贪心:对每一堆相同时刻的任务,每一次尽可能得多生产商品
第二次贪心:对每一堆相同时刻的任务,每一次在保证完成生产量的同时,尽可能地多提高生产力
最后在来正确的贪心策略,在完成任务的同时尽可能得提高生产力,但是怎么尽可能得提高?先按时间对任务排序,对每一个状态,依次对每个任务进行计算,首先要设置可以增加的生产力为最大为这个任务与上个任务的时间之差。然后遍历之后所有的任务,得到能增加的生产力的最小值就是能增加的生产力。
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#define fi first
#define se second
//#include<stdlib.h>
//#include <time.h>
//srand((unsigned)time(NULL));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
using namespace std;
const double eps = 1e-7;
const int N = 1e6 + 10;
int n;
struct node{
int t;
ll g, m;
bool operator<(const node& b) const {
return t < b.t;
}
node() {}
node(int _t, ll _g, ll _m) {
t = _t;
g = _g; m = _m;
}
}a[20], p[20];
ll f(ll st, ll cnt, ll need) {
ll a = 1;
ll b = st - cnt;
ll c = need - st * cnt;
ll derta = b * b - 4 * a * c;
if (derta < 0) return -1;
return floor((-b + sqrt(derta)) / 2.0 / a);
}
bool judge(int s) {
p[0] = node(0, 0, 0);
int tot = 0;
for (int i = 0; i < n; i++) {
if ((s >> i) & 1) p[++tot] = a[i];
}
ll have = 0, v = 1;
for (int i = 1; i <= tot; i++) {
ll t = p[i].t - p[i - 1].t;
ll sum = 0;
for (int j = i; j <= tot; j++) {
sum += p[j].g;
if (have >= sum) continue;
t = min(t, f(v, p[j].t - p[i - 1].t, sum - have));
}
if (t < 0) return false;
v += t;
have += v * (p[i].t - p[i - 1].t - t) - p[i].g;
}
return true;
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%lld%lld", &a[i].t, &a[i].g, &a[i].m);
}
sort(a, a + n);
ll ans = 0;
for (int s = 0; s < (1 << n); s++) {
if (judge(s)) {
ll res = 0;
for (int i = 0; i < n; i++) {
if ((s >> i) & 1) res += a[i].m;
}
ans = max(ans, res);
}
}
printf("%lld\n", ans);
return 0;
}