T1
题目
有一个N个数的序列A:1,2,……,N。有一个后进先出容器D,容器的容量为C。如果给出一个由1到N组成的序列,那么可否由A使用容器D的插入和删除操作得到。
INPUT
第1行,2个整数T和C,空格分隔,分别表示询问的组数和容器的容量,1≤C≤N。
第2到T+1行,每行的第1个整数N,表示序列的元素数。接下来N个整数,表示询问的序列。
OUTPUT
T行。若第i组的序列能得到,第i行输出Yes;否则,第i行输出No,1≤i≤T。
Sample
INPUT
2 2
5 1 2 5 4 3
4 1 3 2 4
OUTPUT
No
Yes
Time Limit
100ms
Memory Limit
10MB
Data range
1≤N≤10000 1≤T≤10
Solution
模拟出入栈即可,若当前栈顶是目标数列下一个元素不断出栈,否则将原序列下一个元素入栈
code
#include <bits/stdc++.h>
using namespace std;
int T,C;
int a[10005];
int b[10005];
int stac[10005],top;
int main(){
scanf("%d%d",&T,&C);
while(T--){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i] = i;
}
int now1 = 0,now = 0,top = 0,flag = 0;
while(now < n){
while(a[now + 1] != stac[top] && top <= C && now1 < n)stac[++top] = b[++now1];
if(top > C || (now1 == n && stac[top] != a[now + 1])){
printf("No\n");
flag = 1;
break;
}
stac[top--];
now++;
}
if(flag)continue;
printf("Yes\n");
}
return 0;
}
/*
1 2 5 4 3
1 2 3 4 5
1 3 2 4
1 2 3 4
*/
T2
题目
对n 个正整数,进行如下操作:每一次删去其中两个数 a 和 b,然后加入一个新数:a*b+1,如此下去直到 只剩下一个数。所有按这种操作方式最后得到的数中,最大的为max,最小的为min,计算max-min。
INPUT
第1行:n,数列元素的个数。
第2行:n 个用空格隔开的数x。
OUTPUT
1行,所求max-min。
Sample
INPUT
3
2 4 3
OUTPUT
2
Time Limit
100ms
Memory Limit
64MB
Data range
1<=n<=16 x<=10
Solution
贪心,不断取最大相乘和不断取最小相乘
code
#include <bits/stdc++.h>
using namespace std;
int n;
int a[100005],mx;
bool used[100005];
int maxx,minn;
priority_queue<int> q1,q2;
int main(){
scanf("%d",&n);
mx = n;
minn = 1e9;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
q1.push(a[i]);
q2.push(-a[i]);
}
while(q1.size() > 1){
int x = q1.top();q1.pop();
int y = q1.top();q1.pop();
q1.push(x * y + 1);
}
maxx = max(maxx,q1.top());
minn = min(minn,q1.top());
while(q2.size() > 1){
int x = -q2.top();q2.pop();
int y = -q2.top();q2.pop();
q2.push(-(x * y + 1));
}
maxx = max(maxx,-q2.top());
minn = min(minn,-q2.top());
printf("%d",maxx - minn);
return 0;
}
T3
题目
给定一棵二叉树T,每个结点赋一个权值。计算从根结点到所有结点的最短路径长度。路径长度定义为:路径上的每个顶点的权值和。
INPUT
第1行,1个整数n,表示二叉树T的结点数,结点编号1..n。
第2行,n个整数,空格分隔,表示T的先根序列,序列中结点用编号表示。
第3行,n个整数,空格分隔,表示T的中根序列,序列中结点用编号表示。
第4行,n个整数Wi,空格分隔,表示T中结点的权值,1≤i≤n。
OUTPUT
1行,n个整数,表示根结点到其它所有结点的最短路径长度。
Sample
INPUT
4
1 2 4 3
4 2 1 3
1 -1 2 3
OUTPUT
1 0 3 3
Time Limit
1000ms
Memory Limit
10MB
Data range
1≤n≤20000 -10000≤Wi≤10000
Solution
难点在于前中根序列得到树,需要用类似线段树的方法递归下去建树
code
#include <bits/stdc++.h>
using namespace std;
int n;
int fir[100005];
int mid[100005];
int val[100005];
long long dis[100005];
bool inq[100005];
struct Node{
int lef,rig;
}v[100005];
int dfs(int fir1,int fir2,int mid1,int mid2){
int rootIdx;
for(int i=mid1;i<=mid2;i++) {
if(mid[i] == fir[fir1]) {
rootIdx = i;
break;
}
}
if(rootIdx != mid1) {
v[fir[fir1]].lef = dfs(fir1 + 1,fir1 + (rootIdx - mid1),mid1,rootIdx - 1);
}
if(rootIdx != mid2) {
v[fir[fir1]].rig = dfs(fir1 + (rootIdx - mid1) + 1,fir2,rootIdx + 1,mid2);
}
return fir[fir1];
}
void spfa(){
queue<int> q;
q.push(fir[1]);
inq[fir[1]] = 1;
while(!q.empty()){
int u = q.front();q.pop();
inq[u] = 0;
if(v[u].lef){
int to = v[u].lef;
if(dis[to] > dis[u] + val[to]){
dis[to] = dis[u] + val[to];
if(!inq[to]){
q.push(to);
inq[to] = 1;
}
}
}
if(v[u].rig){
int to = v[u].rig;
if(dis[to] > dis[u] + val[to]){
dis[to] = dis[u] + val[to];
if(!inq[to]){
q.push(to);
inq[to] = 1;
}
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)dis[i] = 300000000;
for(int i=1;i<=n;i++){
scanf("%d",&fir[i]);
v[i].lef = v[i].rig = 0;
}
for(int i=1;i<=n;i++)
scanf("%d",&mid[i]);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
dis[fir[1]] = val[fir[1]];
dfs(1,n,1,n);
spfa();
for(int i=1;i<=n;i++){
printf("%lld",dis[i]);
if(i != n)printf(" ");
}
return 0;
}
/*
6
1 2 4 5 3 6
4 2 5 1 3 6
1 2 3 4 5 6
*/
T4
题目
组装一个产品需要 n 个零件。生产每个零件都需花费一定的时间。零件的生产可以并行进行。有些零件的生产有先后关系,只有一个零件的之前的所有零件都生产完毕,才能开始生产这个零件。如何合理安排工序,才能在最少的时间内完成所有零件的生产。在保证最少时间情况下,关键方案有多少种,关键方案是指从生产开始时间到结束时间的一个零件生产序列,序列中相邻两个零件的关系属于事先给出的零件间先后关系的集合,序列中的每一个零件的生产都不能延期。
INPUT
第1行,2个整数n和m,用空格分隔,分别表示零件数和关系数,零件编号1..n 。
第2行,n个整数Ti,用空格分隔,表示零件i的生产时间,1≤i≤n 。
第3到m+2行,每行两个整数i和j,用空格分隔,表示零件i要在零件j之前生产。
OUTPUT
第1行,1个整数,完成生产的最少时间。
第2行,1个整数,关键方案数,最多100位。
如果生产不能完成,只输出1行,包含1个整数0.
Sample
INPUT
4 4
1 2 2 1
1 2
1 3
2 4
3 4
OUTPUT
4
2
Time Limit
200ms
Memory Limit
64MB
Data range
1≤n≤10000 0≤m≤100000 1≤Ti≤100
Solution
关键路径,利用拓扑排序递推得出每个事件发生的最早,再通过加法原理与关键活动得出路径数,由于答案过大需要高精
code
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
struct Add{
int a[N];
Add(){memset(a,0,sizeof a);}
void read(){
memset(a,0,sizeof a);
char s[N];
scanf("%s",s+1);
a[0] = strlen(s+1);
for(int i=a[0];i>=1;i--)
a[a[0]-i+1] = s[i] - '0';
}
void get(int x){
memset(a,0,sizeof a);
while(x){
a[++a[0]] = x % 10;
x /= 10;
}
}
void print(){
for(int i=a[0];i>=1;i--)
printf("%d",a[i]);
}
Add operator +(const Add &b){
Add res;res.a[0] = max(a[0],b.a[0]);
for(int i=1;i<=res.a[0];i++)
res.a[i] += a[i] + b.a[i],res.a[i+1] += res.a[i]/10,res.a[i] %= 10;
if(res.a[res.a[0]+1])res.a[0] ++;
return res;
}
};
int n,m;
int to[120005],nex[120005],head[120005],ce;
int val[120005];
int ve[120005],vl[120005];
int ee[120005],el[120005];
int topoarr[120005],now;
int in[120005];
int in1[120005];
int T[120005];
Add ans[120005];
void add(int u,int v,int w){
to[++ce] = v,nex[ce] = head[u],head[u] = ce,val[ce] = w;
}
void topo(){
queue<int> q;
q.push(0);
topoarr[++now] = 0;
while(!q.empty()){
int u = q.front();q.pop();
topoarr[++now] = u;
for(int i=head[u];i;i=nex[i]){
int v = to[i];
in[v]--;
if(ve[u] + val[i] > ve[v])
ve[v] = ve[u] + val[i];
if(!in[v])q.push(v);
}
}
for(int i=1;i<=n;i++)
if(in[i]){printf("0");exit(0);}
for(int i=0;i<=n+1;i++)vl[i] = ve[n + 1];
for(int u=n;u>=0;u--)
for(int i=head[u];i;i=nex[i]){
int v = to[i];
if(vl[v] - val[i] < vl[u])
vl[u] = vl[v] - val[i];
}
}
void bfs(){
queue<int> q;
q.push(0);
ans[0].get(1);
while(!q.empty()){
int u = q.front();q.pop();
for(int i=head[u];i;i=nex[i]){
int v = to[i];
in1[v]--;
ee[i] = ve[u],el[i] = vl[v] - val[i];
if(ee[i] == el[i])
ans[v] = ans[v] + ans[u];
if(!in1[v])q.push(v);
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&T[i]);
add(0,i,T[i]);
in[i]++;
in1[i]++;
add(i,n + 1,0);
in[n + 1]++;
in1[n + 1]++;
}
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
add(u,v,T[v]);
in[v]++;
in1[v]++;
}
topo();
bfs();
printf("%d\n",ve[n + 1]);
ans[n + 1].print();
return 0;
}