个人训练赛第47场

A: 加工零件(最短路)

问题 A: 加工零件时间限制: 1 Sec 内存限制: 128 MB

题目描述

凯凯的工厂正在有条不紊地生产一种神奇的零件,神奇的零件的生产过程自然也很神奇。工厂里有 n 位工人,工人们从 1 ∼ n 编号。某些工人之间存在双向的零件传送带。保证每两名工人之间最多只存在一条传送带。
如果 x 号工人想生产一个被加工到第 L(L > 1) 阶段的零件,则所有与 x 号工人有传送带直接相连的工人,都需要生产一个被加工到第 L− 1 阶段的零件(但 x 号工人自己无需生产第 L − 1 阶段的零件)。
如果 x 号工人想生产一个被加工到第 1 阶段的零件,则所有与 x 号工人有传送带直接相连的工人,都需要为 x 号工人提供一个原材料。
轩轩是 1 号工人。现在给出q张工单,第i张工单表示编号为 ai 的工人想生产一个第 Li 阶段的零件。轩轩想知道对于每张工单,他是否需要给别人提供原材料。他知道聪明的你一定可以帮他计算出来!

输入

第一行两个正整数 n, m 和 q,分别表示工人的数目、传送带的数目和工单的数目。
接下来 m 行,每行两个正整数 u 和 v,表示编号为 u 和 v 的工人之间存在一条零件传输带。保证 u ≠ v。
接下来 q 行,每行两个正整数 a 和 L,表示编号为 a 的工人想生产一个第 L 阶段的零件。

输出

共q行,每行一个字符串 “Yes” 或者 “No”。如果按照第 i张工单生产,需要编号为 1 的轩轩提供原材料,则在第 i行输出 “Yes”;否则在第 i行输出 “No”。注意输出不含引号。

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

【输入样例1】
3 2 6
1 2
2 3
1 1
2 1
3 1
1 2
2 2
3 2【输入样例2】
5 5 5
1 2
2 3
3 4
4 5
1 5
1 1
1 2
1 3
1 4
1 5

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

【输出样例1】
No
Yes
No
Yes
No
Yes 【输出样例2】
No
Yes
No
Yes
Yes

提示

【输入输出样例 1 说明】

编号为 1 的工人想生产第 1 阶段的零件,需要编号为 2 的工人提供原材料。
编号为 2 的工人想生产第 1 阶段的零件,需要编号为 1 和 3 的工人提供原材料。
编号为 3 的工人想生产第 1 阶段的零件,需要编号为 2 的工人提供原材料。
编号为 1 的工人想生产第 2 阶段的零件,需要编号为 2 的工人生产第 1 阶段的零件,需要编号为 1 和 3 的工人提供原材料。
编号为 2 的工人想生产第 2 阶段的零件,需要编号为 1 和 3 的工人生产第 1 阶段的零件,他/她们都需要编号为 2 的工人提供原材料。
编号为 3 的工人想生产第 2 阶段的零件,需要编号为 2 的工人生产第 1 阶段的零件,需要编号为 1 和 3 的工人提供原材料。

【输入输出样例 2 说明】

编号为 1 的工人想生产第 1 阶段的零件,需要编号为 2 和 5 的工人提供原材料。
编号为 1 的工人想生产第 2 阶段的零件,需要编号为 2 和 5 的工人生产第 1 阶段的零件,需要编号为 1,3,4 的工人提供原材料。
编号为 1 的工人想生产第 3 阶段的零件,需要编号为 2 和 5 的工人生产第 2 阶段
的零件,需要编号为 1,3,4 的工人生产第 1 阶段的零件,需要编号为 2,3,4,5 的工人提供原材料。
编号为 1 的工人想生产第 4 阶段的零件,需要编号为 2 和 5 的工人生产第 3 阶段的零件,需要编号为 1,3,4 的工人生产第 2 阶段的零件,需要编号为 2,3,4,5 的工人生产第 1 阶段的零件,需要全部工人提供原材料。
编号为 1 的工人想生产第 5 阶段的零件,需要编号为 2 和 5 的工人生产第 4 阶段的零件,需要编号为 1,3,4 的工人生产第 3 阶段的零件,需要编号为 2,3,4,5 的工人生产第 2 阶段的零件,需要全部工人生产第 1 阶段的零件,需要全部工人提供原材料。

题解

设工人x离工人1的最短路径为d,则工人x生产d阶段的零件,工人1就需要提供原料。如果d是奇数,那么工人x生产大于等于d的奇数的阶段的零件,则工人1就需要提供原料;d如果是偶数也是一样的规律。如果工人x离工人1有奇数最短距离d1,偶数最短距离d2,那么工人x生产大于等于d1的奇数的阶段零件和生产大于等于d2的偶数的阶段零件,则工人1就需要提供原料。
注意:工人1自身离自己有一个d=0的最短距离,所以工人1生产偶数的阶段零件,工人1就需要提供原料。
所以我们需要计算出1到每个点的奇数最短路和偶数最短路。

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+10;
const int INF = 0x3f3f3f3f;
vector<int> g[N];//存边
int d[N][3];//d[i][1]:表示i点到1的奇数最短路,d[i][2] :表示i点到1的偶数最短路
void bfs()
{queue<int> q;q.push(1);memset(d,INF,sizeof(d));//初始化d[1][1]=INF,d[1][2]=0;//1到1的偶数最短距离是0while(!q.empty()){int u=q.front();q.pop();for(int i=0;i<g[u].size();i++){int v=g[u][i];if(d[v][1]>d[u][2]+1||d[v][2]>d[u][1]+1)//最短距离有更新,就入队{if(d[v][1]>d[u][2]+1)d[v][1]=d[u][2]+1;if(d[v][2]>d[u][1]+1)d[v][2]=d[u][1]+1;q.push(v);}}}
}
int main()
{int n,m,q;scanf("%d%d%d",&n,&m,&q);int a,b;for(int i=1;i<=m;i++){scanf("%d%d",&a,&b);g[a].push_back(b);g[b].push_back(a);}bfs();for(int i=1;i<=q;i++){scanf("%d%d",&a,&b);if(b%2){if(d[a][1]<=b) printf("Yes\n");else printf("No\n");}else{if(d[a][2]<=b) printf("Yes\n");else printf("No\n");}}return 0;
}

B: Find the median(线段树+离散化区间)

问题 B: Find the median时间限制: 2 Sec 内存限制: 128 MB

题目描述

Let median of some array be the number which would stand in the middle of this array if it was sorted beforehand. If the array has even length let median be smallest of of two middle elements. For example, median of the array [10,3,2,3,2] is 3 (i.e. ). Median of the array [1,5,8,1] is 1 (i.e.).

At first, you’re given an empty sequence. There are N operations. The i-th operation contains two integers Li and Ri. This means that adding Ri-Li+1 integers Li, Li+1, … , Ri into the sequence. After each operation, you need to find the median of the sequence.

输入

The first line of the input contains an integer N (1≤N≤400000) as described above.

The next two lines each contains six integers in the following format, respectively:

- X1 X2 A1 B1 C1 M1
- Y1 Y2 A2 B2 C2 M2

These values are used to generate Li, Ri as follows:

We define:
- Xi=(A1×Xi−1+B1×Xi−2+C1) module M1, for i = 3 to N
- Yi=(A2×Yi−1+B2×Yi−2+C2) module M2, for i = 3 to N

We also define:
- Li=min(Xi,Yi)+1, for i=1 to N.
- Ri=max(Xi,Yi)+1, for i=1 to N.

Limits:
1≤N≤400000
0≤A1<M1
0≤A2<M2
0≤B1<M1
0≤B2<M2
0≤C1<M1
0≤C2<M2
0≤X1<M1
0≤X2<M1
0≤Y1<M2
0≤Y2<M2
1≤M1≤109
1≤M2≤109

输出

You should output N lines. Each line contains an integer means the median.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

5
3 1 4 1 5 9
2 7 1 8 2 9

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

3
4
5
4
5

提示

L = [3, 2 ,4, 1, 7]

R = [4, 8, 8, 3, 9]

题解

寻找区间中位数,我想大家肯定有不少想法。例如离散化+树状数组+二分或者就是离散化+线段树。
我在这里介绍的就是离散化+线段树的方法,其实这种线段树是权值线段树。
具体啥是权值线段树呢?我之后写主席博客的时候会详细讲。你可以理解为一个维护点出现次数的线段树,它可以算出当前序列中的第K大值。
这里的权值线段树较其他线段树的难点就是离散化和线段树维护的是左闭右开区间内的数出现的个数。
为啥要左闭右开呢?
我们看这样一个例子:
(3,3),(3,5),(5,5)
直接离散化:(1,1)(1,2)(2,2)
那么此时这样看(1,1) + (2,2) = (1,2)是成立的,但是还原到离散化之前是(3,3) + (5,5) = (3,5),显然不成立,左边式子缺少(4,4)。
如果区间是左闭右开的,那么原序列:(3,4),(3,6),(5,6)
离散化:(1,2),(1,4)(3,4),记得还要还原为(1,1),(1,3,)(2,3),明显的是它与闭区间不同的是,它没有区间的缺失,(3,3)与(5,5)之间的(4,4)被离散后的(2,2) 表示。
我们可以找到类似的数据发现左闭右开的区间可以避免一些闭区间的区间缺失或者冲突。

在最后确定中位数的时候,只需要去找到对应的区间(最后落在点上面),算出区间的数都出现多少次time = sum/(R+ 1 - L);确定数字num = L + (rank - 1)/time;其中rank - 1是防止rank = time时,中位数也是L这个数,但是变成了L+1。

如果你是写线段树的时候不记录对应节点的区间的左右端点的人,那么你最好注意一下写更新(区间修改)的代码时,分为当前区间中点Mid在修改区间的左边,右边,和中间,也就是修改区间左右端点[l,r]的信息要跟着区间分布变化,因为这样写区间信息全部跟着函数走,而区间的长度会影响点的修改。例如代码Tree[index] += (disc[R + 1] - disc[L]);如果你对要修改的区间永远是l,r不变,那么在左,右子树中各有多少多长区间都不清楚,那么 (disc[R + 1] - disc[L])的长度就不是对应子树内含有修改区间的长度。

AC代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 4e5 + 10;
ll x[maxn], y[maxn];
struct Tree{int l, r;ll sum, len, lazy;
}tree[maxn << 3];
int b[maxn << 1];
inline void pushup(int cur){tree[cur].sum = tree[cur << 1].sum + tree[cur << 1 | 1].sum;
}
inline void build(int l, int r, int cur) {tree[cur].l = l;tree[cur].r = r;tree[cur].sum = tree[cur].lazy = 0;if(l == r) {tree[cur].len = b[l + 1] - b[l];return;}int mid = l + r >> 1;build(l, mid, cur << 1);build(mid + 1, r, cur << 1 | 1);tree[cur].len = tree[cur << 1].len + tree[cur << 1 | 1].len;
}
inline void pushdown(int cur){if(tree[cur].lazy != 0){tree[cur << 1].lazy += tree[cur].lazy;tree[cur << 1].sum  += tree[cur].lazy * tree[cur << 1].len;tree[cur << 1 | 1].lazy += tree[cur].lazy;tree[cur << 1 | 1].sum  += tree[cur].lazy * tree[cur << 1 | 1].len;tree[cur].lazy = 0;}
}inline void update(int cur, int l, int r) {if(l <= tree[cur].l && tree[cur].r <= r) {tree[cur].sum += tree[cur].len ;tree[cur].lazy++;return ;}pushdown(cur);int mid = tree[cur].l + tree[cur].r >> 1;if(l <= mid) update(cur << 1, l, r);if(mid < r) update(cur << 1 | 1, l, r);pushup(cur);
}
inline int query(int cur, ll pos) {if(tree[cur].l == tree[cur].r) {ll tmp = tree[cur].sum / tree[cur].len;return b[tree[cur].l] + (pos - 1) / tmp;}pushdown(cur);if(pos <= tree[cur << 1].sum) return query(cur << 1, pos);else return query(cur << 1 | 1, pos - tree[cur << 1].sum);
}
int main()
{int n, a1, a2, b1, b2, c1, c2, m1, m2;scanf("%d", &n);scanf("%lld %lld %d %d %d %d", &x[1], &x[2], &a1, &b1, &c1, &m1);scanf("%lld %lld %d %d %d %d", &y[1], &y[2], &a2, &b2, &c2, &m2);for(int i = 3; i <= n; i++) {x[i] = (1ll * a1 * x[i - 1] + 1ll * b1 * x[i - 2] + c1) % m1;y[i] = (1ll * a2 * y[i - 1] + 1ll * b2 * y[i - 2] + c2) % m2;}int len = 0;for(int i = 1; i <= n; i++) {ll l, r;l = min(x[i], y[i]) + 1;r = max(x[i], y[i]) + 1;x[i] = l;y[i] = r;b[++len] = l;b[++len] = r + 1;}sort(b + 1, b + len + 1);len = unique(b + 1, b + len + 1) - (b + 1);for(int i = 1; i <= n; i++) {x[i] = lower_bound(b + 1, b + len + 1, x[i]) - b;y[i] = lower_bound(b + 1, b + len + 1, y[i] + 1) - b;}build(1, len - 1, 1);ll sum = 0;for(int i = 1; i <= n; i++) {update(1, x[i], y[i] - 1);sum += b[y[i]] - b[x[i]];printf("%d\n", query(1, (sum + 1) / 2));}return 0;
}

C: Bracket Sequencing(排序)

问题 C: Bracket Sequencing时间限制: 1 Sec 内存限制: 128 MB

题目描述

A bracket sequence is a string that is one of the following:
1.An empty string;
2.The concatenation of (, A, and ) in this order, for some bracket sequence A ;
3.The concatenation of A and B in this order, for some non-empty bracket sequences A and B /
Given are N strings Si. Can a bracket sequence be formed by concatenating all the N strings in some order?

Constraints
1≤N≤106
The total length of the strings Si is at most 106.
Si is a non-empty string consisting of ( and ).

输入

Input is given from Standard Input in the following format:

N
S1
:
SN

输出

If a bracket sequence can be formed by concatenating all the N strings in some order, print Yes; otherwise, print No.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

【样例1】
2
)
(()
【样例2】
2
)(
()
【样例3】
4
((()))
((((((
))))))
()()()
【样例4】
3
(((
)
)

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

【样例1】
Yes
【样例2】
No
【样例3】
Yes
【样例4】
No

提示

样例1解释:Concatenating (() and ) in this order forms a bracket sequence.

题解

题目大意:

给定n个只包括( )的序列,判断是否可以将这n个序列合成一个合法括号序列。

n<=1e6

题目解法:

首先我们很容易观察到对于每一个序列我们只需要维护两个值:总和和最小前缀和(’(’=1,’)’=-1),分别即为val[i]和mn[i]

首先如果所有字符串的总和加起来不为0显然无解

我们需要找到某种排序,对于任意一个i,第i个字符串的最小前缀mn[i] 和 前面所有字符串的val总和 之和>=0

一开始想到了一种贪心取法 即在所有当前可取的字符串中选择总和最大的那一个。但这个好像得用线段树套有序数组写起来很麻烦还可能超时。

观察到前后两个字符串的相对位置不会影响除他们以外其他前缀的合法性,考虑排序

对于相邻的两个字符串i,j(i<j),i一定在j前面需要满足以下条件:(注意这里的一定,就像我们想从大到小排序数组时重新定义的cmp函数用的是a>b而不是a>=b,这里的判定条件放的是一定满足的条件,不然会出问题)

因此cmp函数的写法就是return (mn[i]>mn[j]&&val[i]>0)||(mn[i]-val[i]<mn[j]-val[j]&&val[j]<0)

*然后check一边中间会不会出问题就好了*

AC代码

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char a[1005000];
struct node
{string str;int flag,flag1,flag2;
};
vector<node>v;
bool cmp(node a,node b)
{if(a.flag!=b.flag)return a.flag<b.flag;elsereturn a.flag1-a.flag2>b.flag1-b.flag2;
}
stack<char>s;
string tmp;
int main()
{int n;scanf("%d",&n);for(int i=1; i<=n; i++){scanf("%s",a+1);tmp="";int flag1=0,flag2=0,flag=0;for(int j=1; a[j]; j++){if(a[j]=='(')s.push('(');else{if(s.empty())tmp.push_back(')'),flag2++;elses.pop();}}while(!s.empty()){tmp.push_back(s.top());flag1++;s.pop();}if(tmp.empty())continue;if(flag1!=0&&flag2==0)flag=1;else if(flag1!=0&&flag2!=0)flag=2;else if(flag1==0&&flag2!=0)flag=3;v.push_back({tmp,flag,flag1,flag2});}sort(v.begin(),v.end(),cmp);for(int i=0; i<v.size(); i++){for(int j=0; j<v[i].str.size(); j++){if(v[i].str[j]=='(')s.push('(');else{if(s.empty())return 0*puts("No");elses.pop();}}}if(!s.empty())return 0*puts("No");puts("Yes");
}

D: Balanced Cow Breeds(dp转移)

问题 D: Balanced Cow Breeds时间限制: 1 Sec 内存限制: 64 MB

题目描述

Farmer John usually brands his cows with a circular mark, but his branding iron is broken, so he instead must settle for branding each cow with a mark in the shape of a parenthesis – (. He has two breeds of cows on his farm:
Holsteins and Guernseys. He brands each of his cows with a parenthesis-shaped mark. Depending on which direction the cow is facing, this might look like either a left parenthesis or a right parenthesis.

FJ’s N cows are all standing in a row, each facing an arbitrary direction, so the marks on the cows look like a string of parentheses of length N. Looking at this lineup, FJ sees a remarkable pattern: if he scans from left to right through just the Holsteins (in the order they appear in the sequence), this gives a balanced string of parentheses; moreover, the same is true for the Guernseys! To see if this is truly a rare event, please help FJ compute the number of possible ways he could assign breeds to his N cows so that this property holds.

There are several ways to define what it means for a string of parentheses to be “balanced”. Perhaps the simplest definition is that there must be the same total number of ('s and )'s, and for any prefix of the string, there must be at least as many ('s as )'s. For example, the following strings are all balanced:
()
(())
()(()())

while these are not:
)(
())(
((())))

输入

* Line 1: A string of parentheses of length N (1 <= N <= 1000).

输出

* Line 1: A single integer, specifying the number of ways FJ can assign breeds to cows so that the Holsteins form a balanced subsequence of parentheses, and likewise for the Guernseys. Since the answer might be a very large number, please print the remainder of this number when divided by 2012 (i.e., print the number mod 2012). Breed assignments involving only one breed type are valid.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

(())

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

6

提示

The following breed assignments work:
(())
HHHH

(())
GGGG

(())
HGGH

(())
GHHG

(())
HGHG

(())
GHGH

提交状态

题解

所以,我用了dp转移,开两个状态:

  前一个  代表 H 还没匹配的前括号数;后一个  代表 G 还没匹配的前括号数;

再把空间滚一滚,讨论一下是 ‘(’ 还是 ‘)’ ,放 H 还是 G ,大力转移;

AC代码

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int mod=2012;
char s[1005];
int n,f[1005][1005],g[1005][1005];//f是之前的状态,g是当前的状态。
int main()
{scanf("%s",s+1);n=strlen(s+1);int oo=0;f[0][0]=1;//开始自然一个都没有。。for(int i=1;i<=n;++i){if(s[i]=='('){oo++;//oo维护还没匹配的左括号总数。for(int j=0;j<=oo;++j){//j枚举的是 H 的左括号还没匹配的数量。if(j) g[j][oo-j]=(g[j][oo-j]+f[j-1][oo-j])%mod;//左括号变成 Hif(oo-j) g[j][oo-j]=(g[j][oo-j]+f[j][oo-j-1])%mod;//左括号变成 G}}else if(s[i]==')'){oo--;//同上for(int j=0;j<=oo;++j){//同上g[j][oo-j]=(g[j][oo-j]+f[j+1][oo-j])%mod;//一个 H 被匹配掉了g[j][oo-j]=(g[j][oo-j]+f[j][oo-j+1])%mod;//一个 G 被匹配掉了}}for(int j=0;j<=oo;++j) f[j][oo-j]=g[j][oo-j],g[j][oo-j]=0;//滚存一下}printf("%d",f[0][0]);//最后肯定没有不匹配的,所以直接输出f[0][0]。return 0;
}

E: Candy Piles(博弈论&&建模)

问题 E: Candy Piles时间限制: 2 Sec 内存限制: 256 MB

题目描述

There are N piles of candies on the table. The piles are numbered 1 through N. At first, pile i contains ai candies.

Snuke and Ciel are playing a game. They take alternating turns. Snuke goes first. In each turn, the current player must perform one of the following two operations:

Choose a pile with the largest number of candies remaining, then eat all candies of that pile.
From each pile with one or more candies remaining, eat one candy.
The player who eats the last candy on the table, loses the game. Determine which player will win if both players play the game optimally.

Constraints
1≤N≤105
1≤ai≤109

输入

The input is given from Standard Input in the following format:

N
a1 a2 … aN

输出

If Snuke will win, print First. If Ciel will win, print Second.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

2
1 3

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

First

提示

At the beginning of the game, pile 2 contains the most candies. If Snuke eats all candies of this pile, Ciel has no choice but to eat the last candy.

题解

有nn堆糖果,第ii堆有aiai个。

两个人轮流决策,决策分为两种:

1.选择糖果数最多的一堆糖果,并把这堆糖全吃了。

2.在每堆非空的糖果堆里拿一颗糖吃掉。

吃掉最后一颗糖的人输。问你先手必胜还是先手必败。

n≤100000

又是一个打表结论题。

先把aiai从大到小排序。

设fi,jfi,j为删掉前ii大,每堆删掉jj个后是先手必胜还是先手必败。先把所有的fi,jfi,j算出来。

如果都删完了,就先手必胜。

打个表可以发现,一条斜线上的结果相同。

这个结论还是挺好证的。这里就不证了。

直接找到(0,0)(0,0)对应的是哪个点(i,i)(i,i),算出这个点到上方和右方轮廓的距离,只要有一个是偶数,就先手必胜。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int a[100010];
int main()
{int n;int i;scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&a[i]);sort(a+1,a+n+1,greater<int>());int ans;a[0]=a[1];for(i=0;i<=n;i++)if(a[i+1]<=i){ans=(a[i]-i)&1;int j=i+1;while(j<=n&&a[j]==i)j++;if((j-i+1)&1)ans=1;break;}if(ans)printf("First\n");elseprintf("Second\n");return 0;
}

F: Teleporter(思维题)

问题 F: Teleporter时间限制: 1 Sec 内存限制: 128 MB

题目描述

The Kingdom of Takahashi has N towns, numbered 1 through N.
There is one teleporter in each town. The teleporter in Town i (1≤i≤N) sends you to Town Ai.
Takahashi, the king, loves the positive integer K. The selfish king wonders what town he will be in if he starts at Town 1 and uses a teleporter exactly K
times from there.
Help the king by writing a program that answers this question.

Constraints
2≤N≤2×105
1≤Ai≤N
1≤K≤1018

输入

Input is given from Standard Input in the following format:

N K
A1 A2 … AN

输出

Print the integer representing the town the king will be in if he starts at Town 1 and uses a teleporter exactly K times from there.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

【样例1】
4 5
3 2 4 1
【样例2】
6 727202214173249351
6 5 2 5 3 2

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

【样例1】
4
【样例2】
2

提示

样例1解释:If we start at Town 1 and use the teleporter 5 times, our travel will be as follows: 1→3→4→1→3→4.

题解

思路1:城市1所在的通路肯定有环,因为每个点有且只有一个出边,判断k次传送在环外还是环内,tarjan计算机强联通分量的大小即环的大小,还有环外的大小。这种有点麻烦

思路2:还有一种:直接利用状态数组求出环的起点还有环的大小,将1所在通路放进一个数组,计算起点所在数组的下标位置。然后判断k即可

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
int l;//1所连接的环的起点
int dfn[N],low[N];
bool instack[N];
int ans;//记录环的大小
int idex=1;
int len;//1所在的链路的大小
stack<int> s;
vector<int> G[N];
bool flag =1;void tarjan(int u)
{s.push(u);instack[u]=1;len++;int v;dfn[u]=low[u]=idex++;for(int i=0; i<G[u].size(); i++){v=G[u][i];if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}else if(instack[v]){low[u]=min(low[u],dfn[v]);}}if(dfn[u]==low[u]){if(flag){l=u;}while(1){if(flag) ans++;v=s.top();s.pop();instack[v]=0;if(u==v){flag=0;break;}}}
}
int main()
{ll n,k;cin>>n>>k;int u;for(int i=1; i<=n; i++){cin>>u;G[i].push_back(u);}tarjan(1);int answer;int num=len-ans;//链路上除了环的大小以外的大小if(k<=num-1){answer=1;while(k--){answer=G[answer][0];}cout<<answer<<endl;}else{answer=l;k=k-num;k%=ans;while(k--){answer=G[answer][0];}cout<<answer<<endl;}return 0;
}

G: Intervals()

问题 G: Intervals时间限制: 1 Sec 内存限制: 128 MB

题目描述

Consider a string of length N consisting of 0 and 1. The score for the string is calculated as follows:

For each i (1≤i≤M), ai is added to the score if the string contains 1 at least once between the li-th and ri-th characters (inclusive).
Find the maximum possible score of a string.

Constraints
All values in input are integers.
1≤N≤2×105
1≤M≤2×105
1≤li≤ri≤N
|ai|≤109

输入

Input is given from Standard Input in the following format:

N M
l1 r1 a1
l2 r2 a2
:
lM rM aM

输出

Print the maximum possible score of a string.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

【样例1】
5 3
1 3 10
2 4 -10
3 5 10
【样例2】
3 4
1 3 100
1 1 -10
2 2 -20
3 3 -30
【样例3】
1 1
1 1 -10
【样例4】
1 5
1 1 1000000000
1 1 1000000000
1 1 1000000000
1 1 1000000000
1 1 1000000000
【样例5】
6 8
5 5 3
1 1 10
1 6 -8
3 6 5
3 4 9
5 5 -2
1 3 -6
4 6 -7

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

【样例1】
20
【样例2】
90
【样例3】
0
【样例4】
5000000000
【样例5】
10

提示

样例1解释:The score for 10001 is a1+a3=10+10=20.
样例2解释:The score for 100 is a1+a2=100+(−10)=90.
样例3解释:The score for 0 is 0.
样例4解释:The answer may not fit into a 32-bit integer type.
样例5解释:For example, the score for 101000 is a2+a3+a4+a5+a7=10+(−8)+5+9+(−6)=10a2+a3+a4+a5+a7=10+(−8)+5+9+(−6)=10.

题解

AC代码

#include<bits/stdc++.h>
#define int long long
#define II pair<int,int>
#define fi first
#define se second
using namespace std;
const int maxn=2e5+1;
vector<pair<int,int>> gr[maxn] ;
struct nodes
{int lazy=0;int _max=0;
};
nodes st[4*maxn];
void down (int id) {st[id * 2].lazy += st[id].lazy;st[id * 2]._max += st[id].lazy ;st[id * 2 + 1].lazy += st[id].lazy ;st[id * 2 + 1]._max += st[id].lazy ;st[id].lazy = 0 ;
}void update (int id , int l , int r , int u , int v , int val) {if (v < l || r < u) return ;if (u <= l && r <= v) {st[id]._max += val ;st[id].lazy += val ;return ;}int mid = (l + r) / 2 ;down(id) ;update(id * 2 , l , mid , u , v , val) ;update(id * 2 + 1 , mid + 1 , r , u , v , val) ;st[id]._max = max(st[id * 2]._max , st[id * 2 + 1]._max) ;
}int32_t main() {int n,m;cin>>n>>m;while (m--) {int l,r,w;cin>>l>>r>>w;gr[r].push_back(II(l,w));}for (int i=1;i<=n;i++) {update(1,1,n,i,i,st[1]._max) ;for (auto j:gr[i]) {update(1,1,n,j.fi,i,j.se) ;}}int ans=max(0ll,st[1]._max);cout<<ans<<endl;
}

H: Governing sand(贪心)

问题 H: Governing sand时间限制: 3 Sec 内存限制: 128 MB

题目描述

The Wow village is often hit by wind and sand,the sandstorm seriously hindered the economic development of the Wow village.
There is a forest in front of the Wowo village, this forest can prevent the invasion of wind and sand. But there is a rule that the number of tallest trees in the forest should be more than half of all trees, so that it can prevent the invasion of wind and sand. Cutting down a tree need to cost a certain amount of money. Different kinds of trees cost different amounts of money. Wow village is also poor.
There are n kinds of trees. The number of i-th kind of trees is Pi, the height of i-th kind of trees is Hi, the cost of cutting down one i-th kind of trees is Ci.

(Note: “cutting down a tree” means removing the tree from the forest, you can not cut the tree into another height.)

输入

The problem is multiple inputs (no more than 30 groups).
For each test case.
The first line contines one positive integers n(1≤n≤105),the kinds of trees.
Then followed n lines with each line three integers Hi(1≤Hi≤109 )-the height of each tree, Ci(1≤Ci≤200)-the cost of cutting down each tree, and Pi(1≤Pi≤109)-the number of the tree.

输出

For each test case, you should output the minimum cost.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

2
5 1 1
1 10 1
2
5 1 2
3 2 3

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

1
2

题解

对于最高的树我们有两种操作
1.留下最高的树,依次砍掉剩下的树中花费最小的树,使其满足题意
2.砍掉最高的树,维护剩下的树
求出操作1和2的花费,取最小就是答案将n种树按高度从小到大排序,遍历n种树,对于第i高度的树,我们将把第i高的树全部砍掉的花费加上令第i-1高的树作为最高树所需的花费,与令第i高的树为最高所需的花费做比较,选取最小的花费。

AC代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 100005
struct node{ll h,p,c;bool operator <(const node &w)const{return h<w.h;}
}a[maxn];
int n;
ll num[205];//存花费为i的树的数量
int main()
{while(cin>>n){ll cnt=0;for(int i=1;i<=n;i++){cin>>a[i].h>>a[i].c>>a[i].p;cnt+=a[i].c*a[i].p;}for(int i=1;i<=205;i++)num[i]=0;ll ans=cnt,tot=0;sort(a+1,a+1+n);int pos=1;for(int i=1;i<=n;i=pos){pos=i;while(a[i].h==a[pos].h&&pos<=n)pos++;ll sum=0,cost=0;//sum为目前最高树的数量for(int j=i;j<pos;j++){cnt-=a[j].c*a[j].p;sum+=a[j].p;}tot+=sum;//小于等于目前最高树的数量sum=tot-sum*2+1;//还需砍掉多少颗树for(int j=1;sum>0;j++){if(num[j]<=sum){cost+=j*num[j];sum-=num[j];}else{cost+=j*sum;sum=0;}}ans=min(ans,cost+cnt);for(int j=i;j<pos;j++){num[a[j].c]+=a[j].p;}}cout<<ans<<endl;}return 0;
}

I: Colorful Blocks(思维+组合数学)

问题 I: Colorful Blocks时间限制: 1 Sec 内存限制: 128 MB

题目描述

There are N blocks arranged in a row. Let us paint these blocks.
We will consider two ways to paint the blocks different if and only if there is a block painted in different colors in those two ways.
·Find the number of ways to paint the blocks under the following conditions:
·For each block, use one of the M colors, Color 1 through Color M, to paint it. It is not mandatory to use all the colors.
There may be at most K pairs of adjacent blocks that are painted in the same color.
Since the count may be enormous, print it modulo 998244353.

Constraints
·All values in input are integers.
·1≤N,M≤2×105
·0≤K≤N−1

输入

Input is given from Standard Input in the following format:

N M K

输出

Print the answer.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

【样例1】
3 2 1
【样例2】
100 100 0
【样例3】
60522 114575 7559

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

【样例1】
6
【样例2】
73074801
【样例3】
479519525

提示

样例1解释:The following ways to paint the blocks satisfy the conditions: 112, 121, 122, 211, 212, and 221. Here, digits represent the colors of the blocks.

题解

# 枚举相邻的位置有i个,可以视作从n-1个(k,k+1)二元组中选出i个出来,
# 方案数为C(n-1,i).
# 那么剩下的n-i个位置一定不相同,方案数为m*((m-1)^(n-i-1)).

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxm=2e6+5;
const int mod=998244353;
int fac[maxm],inv[maxm];
int n,m,k;
int ppow(int a,int b,int mod)
{int ans=1%mod;a%=mod;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod;b>>=1;}return ans;
}
void init()
{fac[0]=1;for(int i=1; i<maxm; i++)fac[i]=fac[i-1]*i%mod;inv[maxm-1]=ppow(fac[maxm-1],mod-2,mod);for(int i=maxm-2; i>=0; i--)inv[i]=(i+1)*inv[i+1]%mod;
}
int C(int n,int m)
{if(m<0||m>n)return 0;return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void solve()
{init();cin>>n>>m>>k;int ans=0;for(int i=0; i<=k; i++) //枚举颜色相同的相邻位置个数{int t=C(n-1,i);int tt=m*ppow(m-1,n-i-1,mod)%mod;ans=(ans+t*tt%mod)%mod;}cout<<ans<<endl;
}
signed main()
{ios::sync_with_stdio(0);solve();return 0;
}

J: Balanced Trees(点分序和括号序)

问题 J: Balanced Trees时间限制: 1 Sec 内存限制: 64 MB

题目描述

Fascinated by his experience with balanced parentheses so far, Farmer John is curious if you can help him solve one final problem. As it turns out, FJ’s farm is in the shape of a giant tree of N pastures (1 <= N <= 40,000), each of which he has labeled with either ( or ). For example:
‘(’–’(’–’)’–’(’–’)’
| |
‘)’ ‘)’–’(’–’(’
| |
‘)’ ‘(’–’)’–’)’–’)’–’(’

Recall that since his farm is a tree, this means that certain pairs of pastures are connected by corridors so that there is one unique path between any given pair of pastures. FJ believes that some of these paths represent balanced strings of parentheses. In particular, he would like to know, among all such balanced strings represented by paths through the tree, what is the maximum nesting depth one can find. The nesting depth of a balanced string of parentheses is the maximum, over all prefixes of the string, of the excess number of ('s within the prefix. For example, the string ()()() has nesting depth 1, but the string ((()))() has nesting depth 3, as we can see clearly if we count excess ('s for every prefix of the string:
((()))()
12321010

For the example farm above, the deepest string is ((())) with a depth of 3, and can be obtained by taking the path from A to B below:
‘(’–’(’–’)’–’(’–’)’
| |
‘)’ ‘)’–’(’–’(’ < A
| |
‘)’ ‘(’–’)’–’)’–’)’–’(’
^C ^B

Note that this is different than the longest balanced string; for instance (())(()), starting at A and ending at C, has length 8.

Your task is to output the nesting depth of the deepest balanced path in the tree.

输入

* Line 1: A single integer N, the number of nodes in the tree.
* Lines 2…N: Line i+1: A single integer p_(i+1) (1 <= p_(i+1) <= i), denoting an edge between nodes i+1 and p_{i+1} in the tree.
* Lines N+1…2N: Line N+i: Either ( or ), the label of node i.

输出

* Line 1: A single integer, giving the maximum nesting depth of a balanced path.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

15
1
2
1
4
4
6
7
5
9
9
11
12
13
14
(
)
)
(
)
)
(
)
(
(
(
)
)
)
(

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

3

提示

This is the example from the problem description, with the following node labels:
1’(’–4’(’–6’)’–7’(’–8’)’
| |
2’)’ 5’)’–9’(’–10’(’
| |
3’)’ 11’(’–12’)’–13’)’–14’)’–15’(’

题解

Solution Notes (Mark Gordon): We will first consider how to solve the problem where you’re given a string of parenthesis and you want to find the substring that is the deepest balanced parenthesis expression. It’s easier to envision solving the problem in terms of prefix sums. Let f(n) give the number of ‘(’ characters minus the number of ‘)’ characters. It should be clear that the range [a, b) is a balanced parenthesis expression iff f(a)=f(b)=min(f[a], f[a+1], …, f[b]). Moreover the depth of the expression is at least f[z] - f[a] for a <= z <= b.

One way to approach this problem, then, is from the inside out. For each index z we’ll want to find the deepest it could be nested in a balanced parenthesis expression. We can compute this directly by first computing g as max(min(f[0], f[1], …, f[z]), min(f[z], f[z + 1], …, f[n-1])). Then, the claim is, there must exist an a and b such that g=f(a)=f(b)=min(f[a], f[a+1], …, f[b]) so that the deepest z could be nested is f(z) - g.

To see why the a and b must exist we can imagine starting a at z and decrementing it until f(a) equals g. Since f(a) starts out equal to f(z) > g and f(n) changes by at most 1 each index it follows that f(a) will eventually hit g when we’ll terminate. Note that we introduced no elements into our range with f(x) smaller than g (or we would have stopped). Similarly we can do the same for b with incrementing. It should be clear that the balance conditions are now met.

We can apply this to trees in a similar way. Instead of picking an index, z, we will pick an edge, e. From one end we will calculate the maximum difference of ‘(’ and ‘)’ characters and from the other end we will calculate the maximum difference of ‘)’ and ‘(’ characters. And, similar to the linear case, the max depth the edge could be nested at is minimum of the two values.

These maximum differences of ‘(’ and ‘)’ characters (and vice versa) can be calculated using a tree DP. Our state is represented by the edge being processed and the orientation of the edge. Then the maximum difference is either 0 or the maximum for each outgoing edge from our first vertex (other than the edge we’re processing) of the maximum difference including the character at our first vertex.

As an implementation note consider that the basic implementation may visit a node proportional to the number of edges it has and that it does work proportional to the number of edges it has. Without care this will lead to a O(N^2) solution in the worst case. To fix this you need to compute results for all edges incident a node at once in some cases. This is only possible the second time you visit a node, however, otherwise the dependency in calculations becomes cyclic.

AC代码

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cassert>using namespace std;int A[200000];
int B[200000];
int C[200000][2];
int V[100000];
vector<int> E[100000];bool vis[100000][2];int solve(int x, int m) {int& ref = C[x][m == 1];if(ref != -1) return ref;int u = B[x];if(vis[u][m == 1]) {int r = 0;for(int i = 0; i < E[u].size(); i++) {C[E[u][i] ^ 1][m == 1] = max(r, C[E[u][i] ^ 1][m == 1]);r = max(r, m * V[u] + C[E[u][i]][m == 1]);}r = 0;for(int i = E[u].size() - 1; i >= 0; i--) {C[E[u][i] ^ 1][m == 1] = max(r, C[E[u][i] ^ 1][m == 1]);r = max(r, m * V[u] + C[E[u][i]][m == 1]);}return ref;}vis[u][m == 1] = true;ref = max(0, m * V[u]);for(int i = 0; i < E[u].size(); i++) {if(x == (E[u][i] ^ 1)) continue;ref = max(ref, m * V[u] + solve(E[u][i], m));}return ref;
}int main() {int N; cin >> N;assert(1 <= N && N <= 40000);for(int u = 1, id = 0; u < N; u++) {int v; cin >> v; v--;assert(v < u);A[id] = u;B[id] = v;E[u].push_back(id++);A[id] = v;B[id] = u;E[v].push_back(id++);}for(int i = 0; i < N; i++) {char ch; cin >> ch;V[i] = ch == '(' ? 1 : -1;}int res = 0;memset(vis, 0, sizeof(vis));memset(C, -1, sizeof(C));for(int u = 0; u < N; u++) {for(int i = 0; i < E[u].size(); i++) {int id = E[u][i];res = max(res, min(solve(id, 1), solve(id ^ 1, -1)));}}cout << res << endl;
}

Further solution notes contributed by Mayank Pandey: Note that for some string a1 a2 … an of parentheses with an equal number of '('s and ')'s, there always exists some balanced substring with nesting depth at least that of a1 … an. Therefore, it is sufficient to simply find the maximal nesting depth of paths that have an equal number of both parentheses. It is easy to solve this for paths through a particular vertex v in O(n) time where n is the size of the subtree of v. If one chooses v so that all the subtrees of v have size at most half the size of v’s subtree, then the problem can be solved in O(N log N), by solving the problem recursively for the subtrees of v. Such a vertex always exists, and can be found by repeatedly going down subtree of a particular vertex if its size is greater than half the size of the tree. Then, it is easy to see that eventually, the vertex one is at will satisfy the property that all its subtrees are at most half the size of the tree.

K: Skill Up(dfs)

问题 K: Skill Up时间限制: 1 Sec 内存限制: 128 MB

题目描述

Takahashi, who is a novice in competitive programming, wants to learn M algorithms. Initially, his understanding level of each of the M algorithms is 0.
Takahashi is visiting a bookstore, where he finds N books on algorithms. The i-th book (1≤i≤N) is sold for Ci yen (the currency of Japan). If he buys and reads it, his understanding level of the j-th algorithm will increase by Ai,j for each j (1≤j≤M). There is no other way to increase the understanding levels of the algorithms.

Takahashi’s objective is to make his understanding levels of all the M algorithms X or higher. Determine whether this objective is achievable. If it is achievable, find the minimum amount of money needed to achieve it.

Constraints
All values in input are integers.
1≤N,M≤12
1≤X≤105
1≤Ci≤105
0≤Ai,j≤105

输入

Input is given from Standard Input in the following format:

N M X
C1 A1,1 A1,2 ⋯ A1,M
C2 A2,1 A2,2 ⋯ A2,M

CN AN,1 AN,2 ⋯ AN,M

输出

If the objective is not achievable, print -1; otherwise, print the minimum amount of money needed to achieve it.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

【样例1】
3 3 10
60 2 2 4
70 8 7 9
50 2 3 9
【样例2】
3 3 10
100 3 1 4
100 1 5 9
100 2 6 5
【样例3】
8 5 22
100 3 7 5 3 1
164 4 5 2 7 8
334 7 2 7 2 9
234 4 7 2 8 2
541 5 4 3 3 6
235 4 8 6 9 7
394 3 6 1 6 2
872 8 4 3 7 2

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

【样例1】
120
【样例2】
-1
【样例3】
1067

提示

样例1解释:Buying the second and third books makes his understanding levels of all the algorithms 10 or higher, at the minimum cost possible.
样例2解释:Buying all the books is still not enough to make his understanding levels of all the algorithms 10 or higher.

题解

典型的 DFS……

我们考虑 1 − n 1-n1−n 所有的排列组合情况,因为 n 最大只有12,所以时间复杂度可以控制在12以内,然后暴力判断这个排列是否符合条件,符合条件就更新答案即可,AC代码如下:

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{int c,a[20];
}p[20];
int ans[15],v[20];
ll ANS=1e10,sum;
int n,m,u,x;
void dfs(int cnt,int pre){if(cnt==u){sum=0;fill(v,v+20,0);for(int j=0;j<cnt;j++){for(int k=0;k<m;k++)v[k]+=p[ans[j]].a[k];sum+=p[ans[j]].c;}int flag=1;for(int j=0;j<m;j++) if(v[j]<x) {flag=0;break;}if(flag) ANS=min(ANS,sum);return;}for(int j=0;j<=n;j++){if(j>pre){pre=j;ans[cnt]=pre;dfs(cnt+1,pre);}}
}int main()
{cin>>n>>m>>x;for(int i=1;i<=n;i++){cin>>p[i].c;for(int j=0;j<m;j++)cin>>p[i].a[j];}for(u=1;u<=n;u++){dfs(0,0);}if(ANS==1e10) puts("-1");else cout<<ANS;return 0;
}

L: 纪念品(dp)

问题 L: 纪念品时间限制: 1 Sec 内存限制: 128 MB

题目描述

小伟突然获得一种超能力,他知道未来 T 天 N 种纪念品每天的价格。某个纪念品

的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。

每天,小伟可以进行以下两种交易无限次:

1.任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;

2.卖出持有的任意一个纪念品,以当日价格换回金币。

每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。

T 天之后,小伟的超能力消失。因此他一定会在第 T 天卖出所有纪念品换回金币。

小伟现在有 M 枚金币,他想要在超能力消失后拥有尽可能多的金币。

输入

第一行包含三个正整数 T, N, M,相邻两数之间以一个空格分开,分别代表未来天数T,纪念品数量 N,小伟现在拥有的金币数量 M。

接下来 T 行,每行包含 N 个正整数,相邻两数之间以一个空格分隔。第 i 行的 N 个正整数分别为 Pi,1, Pi,2, … … , Pi,N,其中 Pi,j表示第 i 天第j种纪念品的价格。

输出

输出仅一行,包含一个正整数,表示小伟在超能力消失后最多能拥有的金币数量。

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

【输入样例1】
6 1 100
50
20
25
20
25
50【输入样例2】
3 3 100
10 20 15
15 17 13
15 25 16

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

【输出样例1】
305【输出样例2】
217

提示

【样例1解释】

最佳策略是:

第二天花光所有 100 枚金币买入 5 个纪念品 1;

第三天卖出 5 个纪念品 1,获得金币 125 枚;

第四天买入 6 个纪念品 1,剩余 5 枚金币;

第六天必须卖出所有纪念品换回 300 枚金币,第四天剩余 5 枚金币,共 305 枚金币。

超能力消失后,小伟最多拥有 305 枚金币

【样例2解释】

最佳策略是:

第一天花光所有金币买入 10 个纪念品 1;

第二天卖出全部纪念品 1 得到 150 枚金币并买入 8 个纪念品 2 和 1 个纪念品 3,剩 余 1 枚金币;

第三天必须卖出所有纪念品换回216 枚金币,第二天剩余1枚金币,共 217 枚金币。

超能力消失后,小伟最多拥有 217 枚金币。

【数据规模与约定】

对于 10% 的数据,T = 1。

对于 30% 的数据,T ≤ 4, N ≤ 4, M ≤ 100,所有价格 10 ≤ Pi,j ≤ 100。

另有 15% 的数据,T ≤ 100, N = 1。

另有 15% 的数据,T = 2, N ≤ 100。

对于 100% 的数据,T ≤ 100, N ≤ 100, M ≤ 103,所有价格 1 ≤ Pi,j ≤ 104,数据保证任意时刻,小明手上的金币数不可能超过104。

题解

这题是一个标准的动态规划问题。有人问为什么是动态规划?很简单啊,题目要求是最大值。

进一步分析,比较标准的完全背包问题。就是每天都是独立的,反复做背包处理。

首先,我们可以当天买,当天卖,所以可以第一天买了一个纪念品,第二天卖了再买,第三天再卖。所以我们只需处理每一天,完全背包,设 f[i][j] 为 i 个物品,成本为 j 时可以赚到的钱。对应的状态转移方程为

 //不选,或(再)选一个
f[i][j] = max{f[i-1][j], f[i][j-value[i-1][j]] - value[i-1][j] + value[i][j]}

//不选,或(再)选一个
f[i][j] = max{f[i-1][j], f[i][j-value[i-1][j]] - value[i-1][j] + value[i][j]}剩下的就是套用完全背包问题模板。

AC代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{int dp[10005];int a[105][1005];int t,n,m;cin>>t>>n>>m;for(int i=1; i<=t; i++){for(int j=1; j<=n; j++){scanf("%d",&a[i][j]);}}for(int i=1; i<=t; i++){memset(dp,0,sizeof(dp));for(int j=1; j<=n; j++){for(int k=a[i][j]; k<=m; k++){dp[k]=max(dp[k],dp[k-a[i][j]]+a[i+1][j]-a[i][j]);}}m=max(dp[m]+m,m);}cout<<m;return 0;
}

M: Horseshoes(暴搜)

问题 M: Horseshoes时间限制: 1 Sec 内存限制: 64 MB

题目描述

Although Bessie the cow finds every string of balanced parentheses to be aesthetically pleasing, she particularly enjoys strings that she calls “perfectly” balanced – consisting of a string of ('s followed by a string of )'s having the same length. For example:
(((())))

While walking through the barn one day, Bessie discovers an N x N grid of horseshoes on the ground, where each horseshoe is oriented so that it looks like either ( or ). Starting from the upper-left corner of this grid, Bessie wants to walk around picking up horseshoes so that the string she picks up is perfectly balanced. Please help her compute the length of the longest perfectly-balanced string she can obtain.

In each step, Bessie can move up, down, left, or right. She can only move onto a grid location containing a horseshoe, and when she does this, she picks up the horseshoe so that she can no longer move back to the same location (since it now lacks a horseshoe). She starts by picking up the horseshoe in the upper-left corner of the grid. Bessie only picks up a series of horseshoes that forms a perfectly balanced string, and she may therefore not be able to pick up all the horseshoes in the grid.

输入

* Line 1: An integer N (2 <= N <= 5).
* Lines 2…N+1: Each line contains a string of parentheses of length N. Collectively, these N lines describe an N x N grid of parentheses.

输出

* Line 1: The length of the longest perfectly balanced string of horseshoes Bessie can collect. If Bessie cannot collect any balanced string of horseshoes (e.g., if the upper-left square is a right parenthesis), output 0.

样例输入 [Copy](javascript:CopyToClipboard($(’#sampleinput’).text()))

4
(())
()((
(()(
))))

样例输出 [Copy](javascript:CopyToClipboard($(’#sampleoutput’).text()))

8

提示

The sequence of steps Bessie takes to obtain a balanced string of length 8 is as follows:
1())
2)((
345(
876)

题解

在一个字符矩阵里面找一个形如((()))的字符串使得它的长度最长。

从大到小来搜索,矩阵大小确定了,那么可能存在的最长的字符串长度也确定了,是n*n,因为2<=n<=5,所以暴搜完全可以。最长=24,开始暴搜,搜索的过程中可以记录一下,最大可以扩展(的个数,这样下次暴搜的时候就不是从24-2开始,而是从所记录的那个数开始,这个优化应该是对的,不过我ac的时候没有加这个,因为数据量的确太小了。我最先的思路是二分长度,提交wa后发现,会存在某些矩阵,小的长度找不到,大一点就可以找到。这组数据是我当时想到的,现在也会想不起来了。所以后来就直接从大到小暴搜了。。

AC代码

//官方题解
#include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
int N;
bool unvis[7][7];
int graph[7][7]; //-1 is border, 0 is open, 1 is close
int dx[4] = {1,-1,0,0};
int dy[4] = {0,0,1,-1};
int ans = 0;
void calc(int r, int c, int numopen, int numclose, bool second)
{if(numopen == numclose){ans = max(ans, numopen + numclose);return;}//there is no need to check solutions that we know cannot be better than the best answer that we have found so far//this optimization is not required to solve the given test cases within 1 secondif(second && (2*numopen <= ans))return;unvis[r][c] = false;for (int i = 0; i < 4; i++){int r2 = r + dx[i];int c2 = c + dy[i];if(unvis[r2][c2]){if(graph[r2][c2] == 1)calc(r2, c2, numopen, numclose + 1, true);else if(!second)calc(r2, c2, numopen + 1, numclose, false);}}unvis[r][c] = true;
}
int main()
{cin >> N;for (int i = 0; i <= N+1; i++) //adding a border around the grid makes it easier to check if a location is within the grid{unvis[0][i] = unvis[N+1][i] = unvis[i][0] = unvis[i][N+1] = false;graph[0][i] = graph[N+1][i] = graph[i][0] = graph[i][N+1] = -1;}for (int i = 1; i <= N; i++){string s;cin >> s;for (int j = 1; j <= N; j++){unvis[i][j] = true;if(s[j-1] == '(')graph[i][j] = 0;elsegraph[i][j] = 1;}}if(graph[1][1] == 0)calc(1,1,1,0,false);cout << ans << "\n";return 0;
}

2021UPC个人训练赛第47场相关推荐

  1. 2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FFT)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 2021年度训练联盟热身训练赛第四场 H - Rock Paper Scissors(字符串匹配,FF ...

  2. 19级算法训练赛第七场

    19级算法训练赛第七场 传送门:https://vjudge.net/contest/362412#problem/J A - 程序设计:合并数字 蒜头君得到了 n 个数,他想对这些数进行下面这样的操 ...

  3. 2021年度训练联盟热身训练赛第五场

    2021年度训练联盟热身训练赛第五场 链接:https://ac.nowcoder.com/acm/contest/13926 A Binary Seating #include<bits/st ...

  4. 2021年度训练联盟热身训练赛第八场

    目录 2021年度训练联盟热身训练赛第八场 A-Fire on Field 题意 思路 代码 B-Gene Tree 题意 思路 代码 I-Thread Knots 题意 思路 代码 J-Triang ...

  5. 2021年度训练联盟热身训练赛第三场赛后补题

    2021年度训练联盟热身训练赛第三场赛后补题 A Circuit Math [题目分析] [代码展示] B Diagonal Cut [题目分析] [代码展示] C Gerrymandering [题 ...

  6. 2021年度训练联盟热身训练赛第三场(待补)

    文章目录 前言 一.Circuit Math(后缀表达式---栈&&fgets) 二.Diagonal Cut(gcd最大公因数,数论) 三.expected primary-expr ...

  7. 2018-2019赛季多校联合新生训练赛第六场补题与题解(中石油)

    **总结:**这场比赛是我成绩最好的一次,也是打比赛这么多以来第一次拿到银牌(40名)可能因为昨天是我弟弟的生日把哈哈哈哈有他在家里保佑我进银牌区,这场比赛怎么说呢,考点和难度感觉都比上次要高了很多, ...

  8. 2018牛客网暑假ACM多校训练赛(第二场)E tree 动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round2-E.html 题目传送门 - 2018牛客多校赛第二场 E ...

  9. 17暑期ACM俱乐部个人训练赛第1场 (石油oj) 7.24号

    //暑假训练第一场,孤军奋斗,事后各种补题,(ps,说实话,时间点卡的不是很好,12点到17点, 没有午觉,大脑犯困, 各种困,各种累,再者,自己也慢慢的发现 精力开始不放在算法上了, 很多时候在做其 ...

最新文章

  1. NLPIR-KGB知识图谱引擎突破传统数据挖掘束缚
  2. android v4包自动导入吧,android如何导入v4包的源码
  3. 真正的高情商,从学会麻烦别人开始
  4. Vue生命周期通俗理解
  5. 硬盘底座linux,微客智品 篇五十二:机械硬盘如何安放?用奥睿科单盘位移动硬盘底座助力新玩法...
  6. AudioEffect构造流程跟踪 音效库实现(native侧)
  7. 屏幕录像专家V2014(附注册码)
  8. 赤峰中考计算机考试软件,2017年内蒙古赤峰中考信息技术操作考试实施细则
  9. Linux:计算机网络基础
  10. java 504错误怎么解决_前端报504错误如何定位
  11. 如何用python画帆船_简单几步,100行代码用Python画一个蝙蝠侠的logo
  12. EXCEL根据两点经纬度计算距离
  13. APP合集,简单总结一下
  14. Axi:名词解释、乱序、间插、卷绕、窄带访问、非对齐访问、OST
  15. Python 屏幕亮度的调节与息屏
  16. AcWing 1113. 红与黑【《信息学奥赛一本通》】【DFS】【BFS】【Flood Fill】
  17. 一定要做自己最内行的东西,一定要在自己本身的职位上来提升自己
  18. 微软crm 开发笔记 系统配置使用
  19. Android 银联控件支付开发流程
  20. 开发苹果手机 APP,如何保持iOS页面流畅技巧

热门文章

  1. java多媒体工具软件吗_多媒体和图像软件列表
  2. html实现二进制转换,html5前段基础课程(二进制转换篇)
  3. mwp突变检验法在matlab上的实现
  4. python来玩猜字游戏吧
  5. 三个变量存在一个协整方程_6个变量存在3个协整关系能直接回归了吗?
  6. 单片机的片内存储器 片外存储器的内和外是相对于什么啊?
  7. 解决wget报错ERROR: The certificate of ‘xxxxx’ is not trusted
  8. 五子棋AI算法-Alpha Beta剪枝
  9. 小米人均月薪3.99万,没有KPI考核?原来在小米做测试员是这样一种体验
  10. 数据挖掘---分类评估指标和回归问题