比赛链接
C
链接:https://www.nowcoder.com/acm/contest/201/C
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld
题目描述
算术是为数不多的会让Kuon感到棘手的事情。通常她会找Haku帮忙,但是Haku已经被她派去买东西了。于是她向你寻求帮助。
给出一个关于变量x,y的不定方程ax+by=c,显然这个方程可能有多个整数解。Kuon想知道如果有解,使得p2x2+p1x+q2y2+q1y最小的一组整数解是什么。为了方便,你只需要输出p2x2+p1x+q2y2+q1y的最小值。
输入描述:
第一行三个空格隔开的整数a,b,c(0 ≤ a,b,c≤ 105)。
第二行两个空格隔开的整数p1,p2(1 ≤ p1,p2 ≤ 105)。
第三行两个空格隔开的整数q1,q2(1 ≤ q1,q2 ≤ 105)。
输出描述:
如果方程无整数解,输出“Kuon”。
如果有整数解,输出p2x2+p1x+q2y2+q1y的最小值。
示例1
输入
2 2 1
1 1
1 1
输出
Kuon
示例2
输入
1 2 3
1 1
1 1
输出
4
分析: 首先当不定方程有解的同时,后面的方程一定有整数解,故我们强行将
y
=
(
c
−
a
∗
x
)
/
b
y = (c - a * x) / b
y=(c−a∗x)/b 带入,然后化简就可以得到一个关于
x
x
x的二元一次方程. (注意x的取值不是连续的,我们用扩展欧几里得求出一个特解
x
0
x_0
x0,那么
x
=
x
0
+
b
/
g
c
d
(
a
,
b
)
∗
t
x = x_0 + b / gcd(a, b) * t
x=x0+b/gcd(a,b)∗t) , 而且根据式子我们可以知道a是大于0的,故一定是开口向上的一个二次曲线,最小值 在
x
=
−
b
2
∗
a
x=\frac {-b} {2*a}
x=2∗a−b处取, 所以我们只要找到最接近这个位置的x的值就行了. 暴力枚举就行
Code
#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<"\n";
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 11;
const int MOD = (int) 1e9 + 7;
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
/*-----------------------------------------------------------*/
void exgcd(ll a,ll b, ll &d, ll &x, ll &y){
if(!b) { d=a ; x= 1 ,y = 0;}
else {
exgcd(b,a%b,d,y,x);
y-=a/b*x;
}
}
int main(){
ll a, b, c, p1, p2, q1, q2; cin >> a >> b >> c >> p1 >> p2 >> q1 >> q2;
ll x0, y0, d;
double c1 = 1.0;
exgcd(a, b, d, x0, y0);
if(c % d ) cout << "Kuon" <<"\n";
else {
// cout << d <<"\n"
x0 = x0 * (c / d);
double aa = p2 * c1 + q2 * a * a * c1 / (b * b);
double bb = p1 * c1 - a * q1 * c1 / b - q2 * 2 * a * c * c1/ (b * b);
double cc = q1 * c1 * c * c1 / b + q2 * c * c * c1/ (b * b);
// cout << aa << " " << bb << " " << cc << "\n";
ll mid = -bb / ( 2 * aa);
//cout << b / d <<"\n";
ll ans = INFF;
ll bd = b / d;
for(ll i = mid - 1000000; i <= mid + 1000000; i++){
double t = (i * 1.0 - x0) / bd;
//cout << i <<"\n";
if(((ll)t - t) == 0) {
ans = min(ans, (ll)(i * i * aa + bb * i + cc));
// cout << "ok " << i << "\n";
}
}
cout << ans <<"\n";
}
return 0;
}
L
链接:https://www.nowcoder.com/acm/contest/201/L
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
Special Judge, 64bit IO Format: %lld
题目描述
Eagle Jump公司正在开发一款新的游戏。Hifumi Takimoto作为其中的员工,获得了提前试玩的机会。现在她正在试图通过一个迷宫。
这个迷宫有一些特点。为了方便描述,我们对这个迷宫建立平面直角坐标系。迷宫中有两条平行直线 L1:Ax+By+C1=0, L2:Ax+By+C2=0,还有 n 个圆 。角色在直线上、圆上、园内行走不消耗体力。在其他位置上由S点走到T点消耗的体力为S和T的欧几里得距离。
Hifumi Takimoto想从 L1 出发,走到 L2 。请计算最少需要多少体力。
输入描述:
第一行五个正整数 n,A,B,C1,C2 (1≤ n ≤ 1000, -10000 ≤ A,B,C1,C2 ≤ 10000),其中 A,B 不同时为 0。
接下来 n 行每行三个整数 x,y,r(-10000 ≤ x,y ≤ 10000, 1≤ r ≤ 10000) 表示一个圆心为 (x,y),半径为 r 的圆。
输出描述:
仅一行一个实数表示答案。与正确结果的绝对误差或者相对误差不超过 10-4 即算正确。
示例1
输入
2 0 1 0 -4
0 1 1
1 3 1
输出
0.236068
分析: 直接建图跑最短路就行了
代码
#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<"\n";
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 1000;
const int MOD = (int) 1e9 + 7;
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
/*-----------------------------------------------------------*/
struct Edge{
int from, to, nex; double val;
Edge(){}
Edge(int _from, int _to, double _val, int _nex){
from = _from; to = _to; val = _val; nex = _nex;
}
}edge[M];
int head[N], top;
void init(int n){
memset(head, -1, sizeof(int) * (n + 10));
top = 0;
}
void addedge(int a, int b, double c){
edge[top] = Edge(a, b, c, head[a]);
head[a] = top++;
edge[top] = Edge(b, a, c, head[b]);
head[b] = top++;
}
bool vis[N];double dis[N];
void spfa(int s, int t){
queue<int>que;
que.push(s);
for(int i = 0; i <= t; i++) dis[i] = INF * 1.0;
vis[s] = 1; dis[s] = 0;
while(!que.empty()){
int now = que.front(); que.pop();
vis[now] =false;
for(int i = head[now];i != -1; i = edge[i].nex){
Edge e = edge[i];
if(dis[now] + e.val < dis[e.to]) {
dis[e.to] = dis[now] + e.val;
if(!vis[e.to]) {
que.push(e.to);
vis[e.to] = 1;
}
}
}
}
printf("%.5lf\n", dis[t]);
}
double xx[N], yy[N], rr[N];
int main(){
double n, A, B, C1, C2; cin >> n >> A >> B >> C1 >> C2;
int S = 0, T = n + 1;
init(T);
rep(i, 1, n + 1){
static double x, y, r; cin >> x >> y >> r;
xx[i] = x; yy[i] = y; rr[i] = r;
double dis = fabs((A * x + B * y + C1) / sqrt(A * A + B * B)) - r;
dis = max((double)0.0, dis);
// dbg(dis);
addedge(S, i, dis);
dis = fabs((A * x + B * y + C2) / sqrt(A * A + B * B)) - r;
dis = max((double)0.0, dis);
// dbg(dis);
addedge(i, T, dis);
}
rep(i, 1, n + 1){
rep(j, i + 1, n + 1){
double dis = sqrt((xx[i] - xx[j]) * (xx[i] - xx[j]) + (yy[i] - yy[j]) * (yy[i] - yy[j])) - rr[i] - rr[j];
dis = max((double)0.0, dis);
// dbg(dis);
addedge(i, j, dis);
}
}
spfa(S, T);
return 0;
}
J
链接:https://www.nowcoder.com/acm/contest/201/J
来源:牛客网
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld
题目描述
阿尔比恩王国(the Albion Kingdom)潜伏着一群代号“白鸽队(Team White Pigeon)”的间谍。在没有任务的时候,她们会进行各种各样的训练,比如快速判断一个文档有没有语法错误,这有助于她们鉴别写文档的人受教育程度。
这次用于训练的是一个含有n个括号的文档。括号一共有m种,每种括号都有左括号和右括号两种形式。我们定义用如下的方式定义一个合法的文档:
1.一个空的字符串是一个合法的文档。
2.如果A,B都是合法的文档,那么AB也是合法的文档。
3.如果S是合法的文档,那么aSb也是合法的文档,其中a,b是同一种括号,并且a是左括号,b是右括号。
现在给出q个询问,每次询问只考虑文档第l至r个字符的情况下,文档是不是合法的。
输入描述:
第一行两个整数n,m,q(1 ≤ n,m,q ≤ 106)。
第二行有n个空格隔开的整数x,第i个整数xi(0 ≤ xi < m*2)代表文档中的第i个字符是第种括号。另外,如果xi是偶数,它代表一个左括号,否则它代表一个右括号。
接下来q行,每行两个空格隔开的整数l,r(1 ≤ l ≤ r ≤ n),代表询问第l至r个字符构成的字符串是否是一个合法的文档。
输出描述:
输出共q行,如果询问的字符串是一个合法的文档,输出"Yes",否则输出"No"。
示例1
输入
6 4 3
0 2 3 1 4 7
1 4
1 5
5 6
输出
Yes
No
No
分析: 对于任意一个区间 [ l e , r i ] [le, ri] [le,ri]来说,要想是括号匹配的,我们可以得到几个充要条件:
- r i − l e + 1 ri - le + 1 ri−le+1 要是偶数
- 一半的左括号,一半的右括号
- 每个左括号与之相匹配的右括号一定在这个区间中(每个括号如果匹配,有且只有一个括号与之匹配),如果没有匹配的我们定义为INF就好.
只要满足以上条件,那么这个区间一定是可以完全匹配.
我们一个个解决上述问题,首先是个数问题,我们可以打两个前缀表就可以解决. 对于匹配位置,我们可以提前o(n)栈扫一遍得到每个括号匹配的括号位置. 之后在建立线段树,每次查询当前区间里面匹配位置的最大值,只要这个最大值在区间中就好.
Code
#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<"\n"
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = (int) 1e6 + 11;
const int M = (int) 1e6 + 11;
const int MOD = (int) 1e9 + 7;
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
/*-----------------------------------------------------------*/
pii type[N];
int reflect[N];
int sumleft[N], sumright[N];
int mx[N << 2];
void build(int rt, int L, int R){
if(L == R){
mx[rt] = reflect[L];
return ;
}
int mid = (L + R) >> 1;
build(rt << 1, L, mid);
build(rt << 1 | 1, mid + 1, R);
mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
}
int query(int rt, int L, int R, int le, int ri){
if(le <= L && R <= ri){
return mx[rt];
}
int mid = (L + R) >> 1;
if(ri <= mid) return query(rt << 1, L, mid, le, ri);
else if(le > mid) return query(rt << 1 | 1, mid + 1, R, le, ri);
else return max(query(rt << 1, L, mid, le, mid), query(rt << 1 | 1, mid + 1, R, mid + 1, ri));
}
int main(){
int n, m, q; scanf("%d%d%d", &n, &m, &q);
sumleft[0] = sumright[0] = 0;
rep(i, 1, n + 1) {
scanf("%d" ,&type[i].first);
type[i].second = i;
sumleft[i] = sumleft[i - 1] + (type[i].first & 1);
sumright[i] = sumright[i - 1] + !(type[i].first & 1);
reflect[i] = INF;
}
stack<pii>s;
rep(i, 1, n + 1){
if(s.empty()) s.push(type[i]);
else {
if(!(s.top().first & 1) && (type[i].first & 1) && s.top().first == (type[i].first - 1) ) {
reflect[s.top().second] = i;
reflect[i] = s.top().second;
s.pop();
}else s.push(type[i]);
}
}
// rep(i, 1, n + 1) cout << i << " " << reflect[i] << "\n";
build(1, 1, n);
while(q--){
static int l, r; scanf("%d%d", &l, &r);
bool flag = 0;
if((r - l + 1) % 2 == 0 && (sumleft[r] - sumleft[l - 1]) == (r - l + 1) / 2 && (sumleft[r] - sumleft[l - 1]) == (sumright[r] - sumright[l - 1])) {
if(query(1, 1, n, l, r) <= r) flag = 1;
// dbg(l); dbg(r); dbg(query(1, 1, n, l, r));
}
puts(flag ? "Yes" : "No");
}
return 0;
}