C
Description
There is a white sheet of paper lying on a rectangle table. The sheet is a rectangle with its sides parallel to the sides of the table. If you will take a look from above and assume that the bottom left corner of the table has coordinates ( 0 , 0 ) (0,0) (0,0), and coordinate axes are left and bottom sides of the table, then the bottom left corner of the white sheet has coordinates ( x 1 , y 1 ) (x_1,y_1) (x1,y1), and the top right — ( x 2 , y 2 ) (x_2,y_2) (x2,y2).
After that two black sheets of paper are placed on the table. Sides of both black sheets are also parallel to the sides of the table. Coordinates of the bottom left corner of the first black sheet are ( x 3 , y 3 ) (x_3,y_3) (x3,y3), and the top right — ( x 4 , y 4 ) (x_4,y_4) (x4,y4). Coordinates of the bottom left corner of the second black sheet are ( x 5 , y 5 ) (x_5,y_5) (x5,y5), and the top right — ( x 6 , y 6 ) (x_6,y_6) (x6,y6).
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qOLnf5Wd-1636460660745)(10a00436065f72be8a399488eb32ccfcd4676460.png)]
Determine if some part of the white sheet can be seen from the above after the two black sheets are placed. The part of the white sheet can be seen if there is at least one point lying not strictly inside the white sheet and strictly outside of both black sheets.
Input
The first line of the input contains four integers x 1 , y 1 , x 2 , y 2 ( 0 ≤ x 1 < x 2 ≤ 1 0 6 , 0 ≤ y 1 < y 2 ≤ 1 0 6 ) x_1,y_1,x_2,y_2 (0≤x_1<x_2≤10^6,0≤y_1<y_2≤10^6) x1,y1,x2,y2(0≤x1<x2≤106,0≤y1<y2≤106) — coordinates of the bottom left and the top right corners of the white sheet.
The second line of the input contains four integers x 3 , y 3 , x 4 , y 4 ( 0 ≤ x 3 < x 4 ≤ 1 0 6 , 0 ≤ y 3 < y 4 ≤ 1 0 6 ) x_3,y_3,x_4,y_4 (0≤x_3<x_4≤10^6,0≤y_3<y_4≤10^6) x3,y3,x4,y4(0≤x3<x4≤106,0≤y3<y4≤106) — coordinates of the bottom left and the top right corners of the first black sheet.
The third line of the input contains four integers x 5 , y 5 , x 6 , y 6 ( 0 ≤ x 5 < x 6 ≤ 1 0 6 , 0 ≤ y 5 < y 6 ≤ 1 0 6 ) x_5,y_5,x_6,y_6 (0≤x_5<x_6≤10^6,0≤y_5<y_6≤10^6) x5,y5,x6,y6(0≤x5<x6≤106,0≤y5<y6≤106) — coordinates of the bottom left and the top right corners of the second black sheet.
The sides of each sheet of paper are parallel (perpendicular) to the coordinate axes.
Output
If some part of the white sheet can be seen from the above after the two black sheets are placed, print “ Y E S YES YES” (without quotes). Otherwise print “ N O NO NO”.
Solution
没啥好说的,讨论覆盖的情况
被一个黑块覆盖
被两个黑块叠在一起覆盖
有时候恶心题并没有你想象的这么难。。。。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
struct node
{
int x1, y1, x2, y2;
};
struct node a, b, c;
void solve()
{
cin >> a.x1 >> a.y1 >> a.x2 >> a.y2;
cin >> b.x1 >> b.y1 >> b.x2 >> b.y2;
cin >> c.x1 >> c.y1 >> c.x2 >> c.y2;
// single cover
if(b.x1<=a.x1 && b.y1<=a.y1 && b.x2>=a.x2 && b.y2>=a.y2)
{
cout << "NO\n";
return ;
}
if(c.x1<=a.x1 && c.y1<=a.y1 && c.x2>=a.x2 && c.y2>=a.y2)
{
cout << "NO\n";
return ;
}
// respective cover
if(b.x2>=c.x1 && b.x1<=a.x1 && c.x2>=a.x2)
{
int up = min(b.y2, c.y2);
int down = max(b.y1, c.y1);
if(up>=a.y2 && down<=a.y1)
{
cout << "NO\n";
return ;
}
}
if(c.x2>=b.x1 && c.x1<=a.x1 && b.x2>=a.x2)
{
int up = min(b.y2, c.y2);
int down = max(b.y1, c.y1);
if(up>=a.y2 && down<=a.y1)
{
cout << "NO\n";
return ;
}
}
if(b.y1<=c.y2 && b.y2>=a.y2 && c.y1<=a.y1)
{
int left = max(b.x1, c.x1);
int right = min(b.x2, c.x2);
if(left<=a.x1 && right>=a.x2)
{
cout << "NO\n";
return ;
}
}
if(c.y1<=b.y2 && c.y2>=a.y2 && b.y1<=a.y1)
{
int left = max(b.x1, c.x1);
int right = min(b.x2, c.x2);
if(left<=a.x1 && right>=a.x2)
{
cout << "NO\n";
return ;
}
}
cout << "YES\n";
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
E1
Description
The only difference between the easy and the hard versions is the maximum value of k k k.
You are given an infinite sequence of form “112123123412345……” which consist of blocks of all consecutive positive integers written one after another. The first block consists of all numbers from 1 1 1 to 1 1 1, the second one — from 1 1 1 to 2 2 2, the third one — from 1 1 1 to 3 3 3, ……, the i i i-th block consists of all numbers from 1 1 1 to i i i.
So the first 56 56 56 elements of the sequence are “ 11212312341234512345612345671234567812345678912345678910 11212312341234512345612345671234567812345678912345678910 11212312341234512345612345671234567812345678912345678910”. Elements of the sequence are numbered from one. For example, the 1 1 1-st element of the sequence is 1 1 1, the 3 3 3-rd element of the sequence is 2 2 2, the 20 20 20-th element of the sequence is 5 5 5, the 38 38 38-th element is 2 2 2, the 56 56 56-th element of the sequence is 0 0 0.
Your task is to answer q q q independent queries. In the i i i-th query you are given one integer k i k_i ki. Calculate the digit at the position k i k_i ki of the sequence.
Input
The first line of the input contains one integer q ( 1 ≤ q ≤ 500 ) q (1≤q≤500) q(1≤q≤500) — the number of queries.
The i i i-th of the following q q q lines contains one integer k i ( 1 ≤ k i ≤ 1 0 9 ) k_i (1≤k_i≤10^9) ki(1≤ki≤109) — the description of the corresponding query.
Output
Print q q q lines. In the i i i-th line print one digit x i ( 0 ≤ x i ≤ 9 ) x_i (0≤x_i≤9) xi(0≤xi≤9) — the answer to the query i i i, i.e. x i x_i xi should be equal to the element at the position k i k_i ki of the sequence.
Solution
1.策略:先从序列中找到包含第k个数的序列,再从那个序列中找到包含第k个数的数,再从那个数中找到要输出的数。
找到那个数可以用二分实现,找到要输出的数可以直接求出那个数的位数,反过来找到那位即可。
关键在两个二分的check
函数的实现。
在实现前,定义一个compute
函数:
// 返回区间[a, b]的和
ll compute(ll a, ll b)
{
if(a > b)
return 0;
return (a+b)*(b-a+1)/2;
}
2.第一个check
函数
代码如下:
// 前num个序列贡献的位数
ll check1(ll num)
{
// 特判0
if(!num)
return 0;
// compute代表贡献的数字总数
// s代表位数
ll x = 10, s = 1, ans = 0;
while(x-1 <= num)
{
// 分别计算每个位数的数的总和
ans += s*compute((num+1)-(x-1), (num+1)-(x/10));
x *= 10;
s++;
}
// 计算剩余的位数的数的总和
ans += s*compute((num+1)-(num), (num+1)-(x/10));
return ans;
}
3.第二个check
函数
代码如下:
// 第num个序列所贡献的位数
ll check2(ll num)
{
// 特判0
if(!num)
return 0;
// 分段计算
// 1-9, 10-99, 100-999
// s为贡献的位数
ll x = 10, s = 1, ans = 0;
while(x-1 <= num)
{
ans += s*((x-1)-(x/10)+1);
x *= 10;
s++;
}
// 剩余的位数
ans += s*(num-(x/10)+1);
return ans;
}
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
ll t;
ll k;
ll s[500005], len;
ll compute(ll a, ll b)
{
if(a > b)
return 0;
return (a+b)*(b-a+1)/2;
}
// 算出当前结尾为1到num的总位数
ll check1(ll num)
{
if(!num)
return 0;
ll x = 10, s = 1, ans = 0;
while(x-1 <= num)
{
ans += s*compute(num+1-(x-1), num+1-(x/10));
x *= 10;
s++;
}
ans += s*compute(num+1-num, num+1-(x/10));
return ans;
}
ll check2(ll num)
{
if(!num)
return 0;
ll x = 10, s = 1, ans = 0;
while(x-1 <= num)
{
ans += s*(x-x/10);
x *= 10;
s++;
}
ans += s*(num-x/10+1);
return ans;
}
// 输出剩余最后一个1到n序列第k的数
void printLeftAlpha(ll n, ll w)
{
len = 0;
while(n)
{
s[++len] = n%10;
n /= 10;
}
cout << s[len-w+1] << endl;
}
void solve()
{
k = read();
// 开始,先找到k在第几个序列里
// 找到第left个序列,使得第k个数刚好在这个序列里
ll left = 1, right = 1000000000;
while(left < right)
{
ll mid = left + ((right-left)>>1);
if(check1(mid) < k)
left = mid+1;
else
right = mid;
}
// 减去前left-1个序列
// 留下最后一个含k的序列单独讨论
k -= check1(left-1);
// 剩余的,只剩下一个序列
// 找到第一个大于等于剩余k的数
right = left, left = 1;
while(left < right)
{
ll mid = left + ((right-left)>>1);
if(check2(mid) < k)
left = mid+1;
else
right = mid;
}
// 减去前面left-1个数的总位数
k -= check2(left-1);
// 计算该位数的输出位置
printLeftAlpha(left, k);
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
t = read();
while (t--)
solve();
return 0;
}
E2
Description
唯一与E1的不同是数据变大
Code
E1的算法依然适用
F
Description
You work as a system administrator in a dormitory, which has n n n rooms one after another along a straight hallway. Rooms are numbered from 1 1 1 to n n n.
You have to connect all n n n rooms to the Internet.
You can connect each room to the Internet directly, the cost of such connection for the i i i-th room is i i i coins.
Some rooms also have a spot for a router. The cost of placing a router in the i i i-th room is also i i i coins. You cannot place a router in a room which does not have a spot for it. When you place a router in the room i i i, you connect all rooms with the numbers from m a x ( 1 , i − k ) max(1, i−k) max(1,i−k) to m i n ( n , i + k ) min(n, i+k) min(n,i+k) inclusive to the Internet, where k k k is the range of router. The value of k k k is the same for all routers.
Calculate the minimum total cost of connecting all n n n rooms to the Internet. You can assume that the number of rooms which have a spot for a router is not greater than the number of routers you have.
Input
The first line of the input contains two integers n n n and k k k ( 1 ≤ n , k ≤ 2 ⋅ 1 0 5 ) (1≤n,k≤2⋅10^5) (1≤n,k≤2⋅105) — the number of rooms and the range of each router.
The second line of the input contains one string s s s of length n n n, consisting only of zeros and ones. If the i i i-th character of the string equals to ‘ 1 1 1’ then there is a spot for a router in the i i i-th room. If the i i i-th character of the string equals to ‘ 0 0 0’ then you cannot place a router in the i i ii-th room.
Output
Print one integer — the minimum total cost of connecting all n n n rooms to the Internet.
Solution
1.一些题目前提结论
由于安装Wi-Fi的代价也为i,并且k已经固定,所以Wi-Fi越早安装代价越小。
对于此,我们可以先用一个f数组来记录该点后面的最近的1的坐标。
2.dp做法
遍历一遍,先更新dp值(假设不装Wi-Fi,直接前缀加i)
接着去查找i-k点后面的最近的能装Wi-Fi的点的下标
如果该Wi-Fi点能覆盖i点的话
检查其是否比当前答案更小
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MOD 1000000007
#define intmax 2147483647
#define memmax 0x7fffffff
ll n, k;
char s[200005];
ll f[200005]; // 每个点右边的最近的1的下标
ll dp[200005];
void solve()
{
cin >> n >> k;
cin >> (s + 1);
f[n + 1] = MOD;
// 初始化f数组
// 严格意义上 f[i]>=i for all i in [1, n]
for (int i = n; i >= 1; i--)
{
if (s[i] == '1')
f[i] = i;
else
f[i] = f[i + 1];
}
for (int i = 1; i <= n; i++)
{
// 先假设直接装,没有wifi
dp[i] = dp[i - 1] + i;
// 找到i-k点后面第一个wifi的下标
ll pre = f[max(1ll, i - k)];
// 如果该点覆盖了i
// i in [pre-k, pre+k]
// 判断是否开wifi代价少一点
if (pre-k <= i)
dp[i] = min(dp[i], dp[max(pre - k, 1ll) - 1] + pre);
}
cout << dp[n] << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}