A-1 Sequence of Grouped Numbers
A sequence of grouped numbers is defined with the following pattern: the 1st group contains 1 number, which is 0×3+1; the 2nd group contains 2 numbers, which are 0×3+2 and 1×3+2; the 3rd group contains 3 numbers, which are 1×3+3, 2×3+3 and 3×3+3; and so on so forth. In general, the i-th group contains i numbers, which starts from the last number of the previous group plus 1, and is incremented by 3 thereafter for each number. For example, the 3rd group can be explained as the following: it contains 3 numbers, which starts from the last number of the 2nd group (that is 5) plus 1 (which gives 6), and then obtain 9 by incrementing 6 by 3, and finally get 12 by incrementing 9 by 3.
So by definition, the first 10 numbers of this sequence are: 1, 2, 5, 6, 9, 12, 13, 16, 19, and 22. They actually consists of 4 groups: {1}, {2, 5}, {6, 9, 12} and {13, 16, 19, 22}.
Your job is to tell the index of any given number in this sequence.
Input Specification:
Each input file contains one test case. Each case starts from a positive integer n (≤10^5) in a line, which is the number of queries. Then n lines follow, each contains a positive number that is no more than 10^5.
Output Specification:
For each queried number, output in a line its index in the sequence (starting from 1). If the number is not in, output Not Found
instead.
Sample Input:
4
12
16
5941
87654
Sample Output:
6
8
2023
Not Found
题意:就是给定一个序列{1}, {2, 5}, {6, 9, 12} , {13, 16, 19, 22}....,有n次询问,问w出现在第几个位置,没有出现输出Not Found。
解析:特征就是组元素的个数不断+1个,且第i组的第一个值是第i-1组最后一个值+1,然后内部+3,按照这个计算即可,利用map记录位置即可
#include <bits/stdc++.h>
using namespace std;
map<int,int> pos;//映射值对应的位置
void init()
{
int x=1,cnt=1;
pos[1]=1;
for(int i=2;;i++)
{
x++;//第一个提出来
pos[x]=++cnt;
for(int j=2;j<=i;j++)//内部依次+3
{
x+=3;
pos[x]=++cnt;
if(x>1e5) break;
}
if(x>1e5) break;
}
}
void solve()
{
int n;
scanf("%d",&n);
if(pos[n]) printf("%d\n",pos[n]);//找到
else printf("Not Found\n");//未找到
}
int main()
{
init();
int t=1;
scanf("%d",&t);
while(t--) solve();
return 0;
}
A-2 Two Ways In, One Way Out
Consider a special queue which is a linear structure that allows insertions at both ends, yet deletions at one end. Your job is to check, for a given insertion sequence, if a deletion sequence is possible. For example, if we insert 1, 2, 3, 4, and 5 in order, then it is possible to obtain 1, 3, 2, 5, and 4 as an output, but impossible to obtain 5, 1, 3, 2, and 4.
Input Specification:
Each input file contains one test case. For each case, the first line gives 2 positive integers N and K (≤10), which are the number of insertions and the number of queries, respectively. Then N distinct numbers (each no larger than 106) are given in the next line, as the insertion sequence. Finally K lines follow, each contains N inserted numbers as the deletion sequence to be checked.
All the numbers in a line are separated by spaces.
Output Specification:
For each deletion sequence, print in a line yes
if it is indeed possible to be obtained, or no
otherwise.
Sample Input:
5 4
10 2 3 4 5
10 3 2 5 4
5 10 3 2 4
2 3 10 4 5
3 5 10 4 2
Sample Output:
yes
no
yes
no
题意:有一个队列,可以两段插入,但是只能从一段删除,给定长度为n的插入序列和q次询问,每次询问给定一个删除输出序列,问该删除序列是否合法.
解析:可以发现,因为只能从一段删除,给定删除序列,那么原序列的相对位置是固定了,题目保证了互不相同,因此原序列也就确定了,我们还原序列结束后判断是否满足删除序列即可.
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[15],b[15],pos[N],n,q;
bool check()
{
deque<int> q;
int cnt=1;//匹配满足个数
//模拟从左端删除
for(int i=1;i<=n;i++)
{
if(q.size()==0) q.push_back(a[i]);//空的话直接放入
else
{
int x=q.back();
if(pos[a[i]]>pos[x]) q.push_back(a[i]);//相对位置在他后面
else q.push_front(a[i]);//相对位置在他后面
}
while(q.size()&&q.front()==b[cnt]) cnt++,q.pop_front();//如果左端相同
}
if(cnt==n+1) return true;
while(q.size()) q.pop_back();//清空
//模拟从右端删除
cnt=1;
for(int i=1;i<=n;i++)
{
if(q.size()==0) q.push_back(a[i]);
else
{
int x=q.back();
if(pos[a[i]]>pos[x]) q.push_back(a[i]);
else q.push_front(a[i]);
}
while(q.size()&&q.back()==b[cnt]) cnt++,q.pop_back();
}
if(cnt==n+1) return true;
return false;
}
void solve()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
while(q--)
{
for(int i=1;i<=n;i++) scanf("%d",&b[i]),pos[b[i]]=i;//记录每个值出现在哪个位置
if(check()) printf("yes\n");
else printf("no\n");
}
}
int main()
{
int t=1;
//scanf("%d",&t);
while(t--) solve();
return 0;
}
A-3 Popularity of Education Supermarket Categories
In PTA, there is the Education Supermarket which collects all kinds of exam/test problem sets. The sets can be found in several categories. The popularity of a category i is defined to be ni/n+pi/p, where ni and pi are the number of users who have opened a set and the total payment received in category i, respectively; n is the total number of users who have opened a set and p is the total payment received in the supermarket.
Your job is to calculate the popularity of any given category.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤103), which is the total number of problem sets and the categories. Then N lines follow, each describes a set or category in the following format:
ID1 ID2 type n p
where ID1
is the index of this set or category, which is a 3-digit number; ID2
is the index of the category that contains ID1
-- a category may have several sub-categories or contains several problem sets, and each set/category may only belong to one supper category; type
being 1 means that ID1
is a category, or 0 means it is a problem set; if ID1
is a set, then n
is the number of users who have opened it, and p
is the total payment received for this set (both are non-negative integers no more than 105); or if ID1
is a category, there will be no n
or p
following type
.
Note: the supermarket itself is the only root category, and its corresponding ID2
will be given as −1.
Finally, another positive integer M (≤103) is given, and is followed by M category ID
's in the next line.
Output Specification:
For each query of category, we should print in a line its popularity. However, to avoid the lose of accuracy during float number calculations, let's output ni, n, pi and p instead. It is guaranteed that none of n or p is zero.
Note: all the numbers in a line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.
Sample Input:
13
001 -1 1
002 001 1
006 002 0 23 45
007 002 0 108 256
005 002 1
003 001 1
011 003 0 0 0
012 003 0 1 5
004 001 1
013 004 0 200 200
008 005 0 35 78
009 005 0 8 26
010 005 0 1130 1516
5
001 002 003 004 005
Sample Output:
1505 1505 2126 2126
1304 1505 1921 2126
1 1505 5 2126
200 1505 200 2126
1173 1505 1620 2126
题意:总结出来就是一个节点有s1,s2值,给定q次询问,对于节点id,输出id子树的{s1,总树s1,s2,总树s2}。
解析: 也就是树的DFS,把当前节点的贡献加到父节点上即可。
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int s1[N],s2[N],root;//分别记录子树的n,p总和
vector<int> v[N];//存邻边
void dfs(int u,int fa)
{
for(int i=0;i<v[u].size();i++)
{
int j=v[u][i];
if(j==fa) continue;
dfs(j,u);
}
if(fa==-1) return;
s1[fa]+=s1[u];//自身子树的贡献累加到父亲节点上
s2[fa]+=s2[u];
}
void solve()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(y!=-1)
{
v[x].push_back(y);
v[y].push_back(x);
}else root=x;//根节点
if(z==0) scanf("%d%d",&s1[x],&s2[x]);
}
dfs(root,-1);//注意是-1,不能是0,因为根节点编号可能是0
int q;
scanf("%d",&q);
while(q--)
{
int id;
scanf("%d",&id);
printf("%d %d %d %d\n",s1[id],s1[root],s2[id],s2[root]);
}
}
int main()
{
int t=1;
//scanf("%d",&t);
while(t--) solve();
return 0;
}
A-4 Auto Taxi
You are supposed to implement an auto taxi management system: for each customer who is ordering a service, send a command to an auto taxi that can take the shortest time to reach the customer. The rules are:
- One can only get a taxi and set one's destination at some pickup spots.
- Any taxi can accept a command at any time after it shows up in the system.
- Any taxi that is carrying passengers on the road must first send its passengers to their destination, before it can carry the next command;
- If there is no more command, a taxi will stay at the destination of its last passenger and wait;
- If there are many taxis that can reach the customer at the same shortest time, the command will be sent to the one without any passenger on board. If there is still a tie (that is, if all the taxis are carrying passengers, or several taxis are waiting), then pick the one with the smallest index, which is guaranteed to be unique.
Note: If a taxi arrives a destination at the same time as a customer submits an order, the taxi is considered empty, without any passenger on board.
Input Specification:
Each input file contains one test case. For each case, first a map is given in the following format:
In the first line, two positive integers are given: Nv (≤1000) and Ne, which are the total number of pickup spots (hence the spots are indexed from 1 to Nv) and the number of streets connecting them. Then Ne lines follow, each describes a street by
spot1 spot2 time
where spot1
and spot2
are the indices of the two ends of the street, and time
is the positive integer time taken to pass this street, in minutes. It is assumed that no street will take more than 100 minutes to pass. And it is guaranteed that no duplicated information is given for any of the streets.
The next block is for the auto taxis.
In the first line, a positive integer M (≤1000) is given. Then M lines follow. The i-th line describes the status of the i-th taxi (hence the taxis are indexed from 1 to M) in the fomat:
pickup_time pickup_spot destination
means that the taxi has picked up someone from pickup_spot
at pickup_time
, and is driving to destination
. Here pickup_time
is in the form hh:mm
, where hh
is in [00, 23] and mm
is in [00, 59]. When pickup_spot
is the same as destination
, it means that the taxi has no passenger and is waiting for the next command at destination
.
The last block is for customer orders.
In the first line, a positive integer K (≤1000) is given. Then K lines follow, each describes an order in the fomat:
order_time pickup_spot destination
means that one has submitted an order of taxi at order_time
(same format as pickup_time
), going from pickup_spot
to destination
.
It is guaranteed that:
- the orders are given in increasing order of
order_time
; - all the
order_time
's are after the latestpickup_time
given in the taxis block, and are within the same day; pickup_spot
is never the same asdestination
;- all the
pickup_spot
's are connected to each other directly or indirectly; and - there is no one-way street road.
Output Specification:
For each order, output in a line the index of the taxi to be sent to the customer, following the rules given by the problem description.
Sample Input:
7 12
1 2 50
1 3 10
1 4 20
1 5 30
1 6 20
1 7 60
2 3 20
2 4 10
3 5 20
4 6 60
5 7 100
6 7 30
4
07:20 2 1
07:10 4 3
06:40 7 3
07:35 4 4
5
07:40 1 7
07:50 6 3
08:00 7 6
08:10 3 4
08:35 6 5
Sample Output:
2
1
2
3
1
题意:n个点,m条无向道路{点x,点y,所需时间},s个司机{接到第一个顾客的时间,起点,终点},r个人{发送订单时间,起点,终点},对于每个顾客,系统会分配最快到达该顾客的车辆,空车优先,输出每个顾客所乘坐车辆的编号。
规则: 1.一辆车同一时间只能承受一个顾客 2.车辆已经完成上一单但是没有新顾客发送订单,那么他会原地待命 3.如果有许多出租车可以在同一最短时间内到达客户,则会将命令发送给没有乘客的出租车。如果仍然存在平局(也就是说,如果所有的出租车都在载客,或者有几辆出租车在等待),那么就选择ID最小的一辆,这保证是唯一的。
解析:最开始肯定是先跑最短路,但是m最大1e3,Floyd(N^3)肯定会超时,因此可以用n次堆优化Dijkstra,初始完之后,因此对于每次询问,只用到每个车辆的两个信息(完成上一单的结束时间,上一单的终点),因此每次选出答案车辆更新信息即可。
#include <bits/stdc++.h>
using namespace std;
const int N=1e3+5;
typedef pair<int,int> PII;
int dist[N][N];
struct node
{
int ed,nex;//上一单结束时间和上一单终点
}tr[N];
vector<PII> v[N];
bool st[N];
void dijkstra(int rt)//求rt点到每个点的最短路
{
memset(st,false,sizeof st);
priority_queue<PII,vector<PII>,greater<PII>> q;
q.push({0,rt});
dist[rt][rt]=0;
while(q.size())
{
int u=q.top().second;
q.pop();
if(st[u]) continue;
st[u]=true;
for(int i=0;i<v[u].size();i++)
{
int j=v[u][i].first;
int w=v[u][i].second;
if(dist[rt][j]>dist[rt][u]+w)
{
dist[rt][j]=dist[rt][u]+w;
q.push({dist[rt][j],j});
}
}
}
}
void solve()
{
int n,m;
scanf("%d%d",&n,&m);
memset(dist,0x3f,sizeof dist);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
v[x].push_back({y,z});
v[y].push_back({x,z});
}
for(int i=1;i<=n;i++) dijkstra(i);
int s;
scanf("%d",&s);
for(int i=1;i<=s;i++)//车辆
{
int x,y,l,r;
scanf("%d:%d %d %d",&x,&y,&l,&r);
tr[i].ed=x*60+y+dist[l][r];//上一单的结束时间
tr[i].nex=r;//上一单终点
}
int r;
scanf("%d",&r);
for(int i=1;i<=r;i++)//顾客
{
int x,y,sx,sy;
scanf("%d:%d %d %d",&x,&y,&sx,&sy);
int T=x*60+y;//顾客发送订单时间
int mi=1e9,ans=-1;//记录最短到达时间和答案车辆
for(int j=1;j<=s;j++)
{
int w=max(T,tr[j].ed)+dist[tr[j].nex][sx];
//注意是max(T,tr[j].ed),因为没收到订单时候,他们会原地待命
if(w<mi) mi=w,ans=j;
else if(w==mi&&tr[j].ed<=T&&tr[ans].ed>T) ans=j;
}
printf("%d\n",ans);
tr[ans].ed=mi+dist[sx][sy];
//更新上一单完成时间,mi时间到达+sx到sy的花费时间
tr[ans].nex=sy;//更新终点
}
}
int main()
{
int t=1;
//scanf("%d",&t);
while(t--) solve();
return 0;
}