ディレクトリ
問題のCCF-csp201809ソリューション
(スペースで区切っ)タグ:CCFの問題解決
1. 201809から1野菜
タイトル説明
質問番号:201809から1つ
の質問名前:野菜の
制限時間は:1.0秒
メモリ制限を:256.0メガバイト
問題の説明
とN通りに店舗で野菜、行のNに順1で、これらの店舗は、植物を販売しています。
初日、各店舗独自のセット価格。店主は、次の日、その一貫性の野菜や他の店をしたい、すべてのお店は彼自身と近隣のお店の価格に応じてその価格を調整します。具体的には、野菜の各々は、翌日格納し、それらの平均値を(尾メソッドを丸め費やさ)野菜の隣接記憶の最初の日に設定されています。
店舗番号1、唯一の2つの隣接する店舗、店舗数nだけ隣接店舗N-1ため、私は、他の2つの隣接する店舗の数を記憶する、ことを注意I-1及びI + 1 。
各八百屋の最初の日を考えると、野菜の価格各店舗次の日を計算します。
入力フォーマット
入力の最初の行のは、整数n、店舗の数を含んでいます。
2行目は、各店舗の野菜の最初の日に、それぞれ、n個の整数を含みます。
出力フォーマット
それぞれ野菜ストアのnは正の整数であり、次の日を含む出力ライン、。
サンプル入力
。8
。4. 3. 1. 5. 1. 6 9 17
サンプル出力
2213491013
データのサイズと合意された
すべてのユースケースのレビューに、2≤N≤1000を超えない各植物店の初日正の整数10000。
解決
問題の意味によれば、第1の入力データは、続いて、ダウン配列によって格納された(オンライン手法を用いてもよい)\(O(N)\)複雑実行は再び、順次隣接する3つの数値の平均値を出力します。
コードで
//1591298 <13100928923> <王恪楠> 卖菜 11-09 21:28 409B C0X 正确 100 15ms 532.0KB
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 50;
int a[MAXN];
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++){
int t = (a[i - 1] + a[i] + a[i + 1]);
if(i == 1 || i == n) //第一个数和最后一个数的相邻数只有一个,所以求平均数只除以2.
printf("%d ", t / 2);
else
printf("%d ", t / 3);
}
return 0;
}
2. 201809から2食料品の買い物
タイトル説明
質問番号:201809から2つの
質問名:食料品ショッピング
制限時間:1.0秒
メモリ制限を:256.0メガバイト
問題の説明
小さなHとWは、小さな通りに二つの別々の購入食品を来た、彼らは、食料品の買い物のプロセスとして説明し、いくつかの食べ物を買うために店に行くと、その後クック平方隣に行くことができます電車にロードされ、彼らが購入する必要がありますnは野菜なので、それが取り付けられてn個の第2の車することができます。具体的には、小さなN H互いに素な期間の[A1、B1]、[A2有し 、B2] ... [BN]を小さなN-Wが互いに素であるため、負荷の期間[C1、D1]、[C2 、D2] ... [CN、DN] ローディングします。前記時間期間[S、T]場合TSの長さは、この時から時間T Sを表します。
彼らは良い友達であるため、彼らは正方形でチャットする時間をロードして、彼らは話すことができるどのくらいかを知りたいです。
入力フォーマット
入力の最初の行のは、正の整数n、期間の数を含んでいます。
次のn行二つの数がaiをたびに、様々な小H.のBI、説明ローディング
次のn行小Wの各ローディングに説明した2つの数字がCたびに、ジ
出力フォーマットの
出力ライン、正の整数は、2が長く話すことができると述べました。
サンプル入力
。4
。1 3
5 6
。9 13は、
14 15
2 4
5 7
10 11
13 14で
の出力例
3
のデータサイズと合意された
すべてのユースケースのレビューに、1≤N≤2000、愛 <BI <AI + 1、CI < すべてのためのディ<CI + 1、I(1≤I≤n)は、1≤AI、BI、CI有し 、ジ≤1000000。
解決
自分のセクションをロードする2人が重ならないので、私たちはローディングゾーンマークマークで二人になり、その後、すべて再生され二回の間隔はリクエストに応じてマークされています。それはであることができる\(VIS [1 \ cdots M ] \) 記録部マーキング配列。
入力が与えられたので\(a_iを、b_i(C_I、 D_I)\) 私たちは、むしろ間隔エンドポイントよりもマークマーカー間隔を作るときに注意を払う必要がありますので、かなりの数の範囲よりも、およそエンドポイントの範囲です。特定のアプローチは、である([L、R))\ \ マーキング(点\(L \)間隔左端点、\(R&LT \)セクション右点)。
インターバル数の間隔エンドポイントの参照番号、青、黄色の数字
コードで
//1591321 <13100928923> <王恪楠> 买菜 11-09 21:42 473B C0X 正确 100 15ms 4.335MB
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 50;
int vis[MAXN];
int main()
{
int n, m = 0;
scanf("%d", &n);
for(int i = 1; i <= n + n; i ++){
int l, r;
scanf("%d%d", &l, &r);
m = max(m, r);
for(int j = l; j < r; j ++) //将每个区间长度[l,r)打上标记.
vis[j] ++;
}
int ans = 0;
for(int i = 1; i <= m; i ++)
if(vis[i] == 2) //如果一个单位长度被打过两次标记,说明这个单位长度是两人共同装车的时间.
ans ++;
printf("%d", ans);
return 0;
}
3.201809から3要素セレクタ
タイトル説明
質問番号:201809から3つ
の質問名前:要素セレクタの
制限時間:1.0秒
256.0メガバイト:メモリ制限を
解決
大雑把な質問の意味:
我们想要对一个树形(or森林)的字符串结构体进行查找操作。
输入:
第一行为n和m。分别代表输入的字符串个数,和查询个数。
下面的n行每行为一个字符串。给出n个结构体。每行的字符串都以"."为起始且点的个数只能为偶数个(可以为0个),代表这一结构体的缩进等级。(缩进等级大的结构体的前缀为与其最近的等级减2的结构体。)之后的字符串为该结构体的标签(不区分大小写,可统一化为小写),之后如果有"#",则"#"之后的字符串为该结构体的id,id区分大小写,且唯一。
下面的m行每行为一个字符串。给出m个查询操作。
1.形如"tag"的字符串,查询标签为"tag"的结构体的序号。
2.形如"#id"的字符串,查询id为"id"的结构体的序号。
3.形如"tag tag #id #id ..."的字符串,查询从左至右,是否每前一个结构体为后一个结构体的前缀,如果满足,则记录最后一个结构体的序号。遇到"tag"则是对比结构体标签,遇到"#id"对比结构体id。
输出:
将每一个查询得到的序号从小到大输出,然后输出换行。
我们可以用一个结构体来储存每一行的缩进等级(int),标签(string),id(string)。
对于查询1和查询2较为简单,因为数据规模较小,我们可以简单的\(O(n)\)实现。
对于查询3,我们需要用一个栈将所要查询的字符串先储存下来,然后找到栈顶的结构体,再用它的前缀不断递归一一和栈中元素对比。
通过代码
//1599261 <13100928923> <王恪楠> 元素选择器 11-14 21:00 3.233KB C0X 正确 100 15ms 632.0KB
#include <bits/stdc++.h>
using namespace std;
struct Node
{
int fa;
string tag, id; //fa是结构体的父亲节点的序号,tag是标签,id是id值.
}a[500];
int last[500], top; //last是存储每一个缩进等级的最近节点序号,比它小一级(值-2)的节点都以此节点为父亲节点.
string s0, s[500]; //用s[1...n]和top模拟栈.后代选择器时使用.
vector<int> ans; //用以记录答案的向量.
ostream &operator << (ostream &out, const Node &i) //重载<<,输出结构体.(测试程序时用)
{
cout << i.tag << " " << i.id << " " << i.fa;
return out;
}
bool cmp(int i, string ss) //比较函数.如果字符串带#则和id比较.如果字符串不带#则和tag比较,和tag比较时00不区分大小写.
{
string str;
if(ss[0] == '#'){
for(int j = 1; j < ss.length(); j ++)
str += ss[j];
return a[i].id == str;
}
transform(ss.begin(), ss.end(), ss.begin(), ::tolower); //将ss都转变为小写,再和tag作比较.
return a[i].tag == ss;
}
int getfa(int i) //后代选择器.不断地寻找节点的父亲节点,和栈顶字符串作比较.如果能使栈为空,说明后代选择器的所有祖先字符串都能被找到.
{
if(i == 0){ //当找到第一缩进等级,节点没有父亲节点时,就要返回!top的值了.
return !top;
}
if(top == 0){
return 1;
}
if(cmp(i, s[top - 1])){
top --;
}
return getfa(a[i].fa);
}
void print()
{
printf("%d", ans.size());
for(int i = 0; i < ans.size(); i ++)
printf(" %d", ans[i]);
printf("\n");
return ;
}
void split(string ss) //字符串分割,以空格为分割符.分割后入栈.
{
string str;
for(int i = 0; i < ss.length(); i ++){
if(ss[i] == ' '){
s[top ++] = str;
str.clear();
}
else
str += ss[i];
}
s[top ++] = str;
return;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);getchar();
for(int i = 1; i <= n; i ++){
getline(cin, s0); //getline()可以整行输入字符串,而不是遇到空格就停止.
int level, pos = 0, flag = 1;
for(int j = 0; j < s0.length(); j ++){
if(s0[j] != '.' && flag){ //记录缩进等级.
level = j;
flag = 0;
}
if(s0[j] == '#') //判断是否有id.
pos = j;
}
last[level] = i; //这个缩进等级的最近一个序号更新为这个节点的序号.
if(level == 0)
a[i].fa = 0; //如果是第零级,那么它就没有祖先节点,就为0.
else
a[i].fa = last[level - 2]; //否则最近的上一缩进等级的序号就是该节点的祖先.
string tag;
for(int j = level; j < s0.length() && s0[j] != ' '; j ++)
tag += s0[j];
transform(tag.begin(), tag.end(), tag.begin(), ::tolower);
a[i].tag = tag; //存下标签tag(注意tag不区分大小写,那么就统一用小写字母存).
if(pos){
string id;
for(int j = pos + 1; j < s0.length(); j ++) //存下id.
id += s0[j];
a[i].id = id;
}
}
while(m --){
getline(cin, s0);
ans.clear();
top = 0;
split(s0); //分割字符串.如果只有一个字符串,也没有影响.
string t = s[top - 1];
top --;
int mm = top;
for(int i = 1; i <= n; i ++)
if(cmp(i, t)){ //将各个节点和栈顶字符串作比较.
top = mm; //每次查找祖先时,将栈顶指针还原,即将栈还原.
if(getfa(a[i].fa))
ans.push_back(i);
}
print();
}
return 0;
}
4.201809-4 再卖菜
题目描述
试题编号: 201809-4
试题名称: 再卖菜
时间限制: 1.0s
内存限制: 256.0MB
问题描述
在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜。
第一天,每个商店都自己定了一个正整数的价格。店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
注意,编号为1的商店只有一个相邻的商店2,编号为n的商店只有一个相邻的商店n-1,其他编号为i的商店有两个相邻的商店i-1和i+1。
给定第二天各个商店的菜价,可能存在不同的符合要求的第一天的菜价,请找到符合要求的第一天菜价中字典序最小的一种。
字典序大小的定义:对于两个不同的价格序列(a1, a2, ..., an)和(b1, b2, b3, ..., bn),若存在i (i>=1), 使得ai<bi,且对于所有j<i,aj=bj,则认为第一个序列的字典序小于第二个序列。
输入格式
输入的第一行包含一个整数n,表示商店的数量。
第二行包含n个正整数,依次表示每个商店第二天的菜价。
输出格式
输出一行,包含n个正整数,依次表示每个商店第一天的菜价。
样例输入
8
2 2 1 3 4 9 10 13
样例输出
2 2 2 1 6 5 16 10
数据规模和约定
对于30%的评测用例,2<=n<=5,第二天每个商店的菜价为不超过10的正整数;
对于60%的评测用例,2<=n<=20,第二天每个商店的菜价为不超过100的正整数;
对于所有评测用例,2<=n<=300,第二天每个商店的菜价为不超过100的正整数。
请注意,以上都是给的第二天菜价的范围,第一天菜价可能会超过此范围。
解析
本题所考察的知识点是差分约束系统。在白书最短路算法的最后一道例题讲对差分约束系统有所讲解。
本题如何建图?
设第\(i\)个菜店第一天的菜价为\(b[i]\,\),第二天的菜价(即第一天相邻店铺菜价的平均值)为\(a[i]\),\(\sum_{i=0}^{n}b[i] = d[n]\)(即\(b[i]\)的前缀和为\(d[i]\))。
因为差分约束系统不等式一侧只能有两个变量,所以\(d[i]\)为前缀和,即可一般地,把\(a[i]\)相邻的三个数\(b[i-1],b[i],b[i+1]\)的平均值不等式表达为\(3 * a[i] \leq d[i + 1] - d[i - 2] \leq 3*a[i] + 2\).
本题是希望找到最小的\(b[i]\),即是想找到最小的\(d[i] - d[i - 1]\),对应于差分约束系统需要建立形如\(v - u \geq w\)的不等式组,同时建立一条起点为\(u\),终点为\(v\),权值为\(w\)的边,然后找出不等式组的最大值。
当\(i\in[2, n - 1]\)时,\[3 * a[i] \leq d[i + 1] - d[i - 2] \leq 3*a[i] + 2 \Rightarrow \begin{cases} d[i+1] - d[i - 2] \geq 3 * a[i], \\ d[i - 2] - d[i + 1] \geq -3 * a[i] - 2. \end{cases}\]
因为首尾只有两个店铺和它们相邻,所以当\(i \in \{1, n\}\,\)时,\[ \begin{cases} d[2] - d[0] \geq 2 * a[1], \\ d[0] - d[2] \geq -2 * a[1] - 1; \end{cases}\;\; \begin{cases} d[n] - d[n - 2] \geq 2 * a[n], \\ d[n - 2] - d[n] \geq -2 * a[n] - 1. \end{cases}\]
フォームの不等式- \(U \ GEQ W V \) を添加した\(U \ V \)に重み値\(W \)側。
我々は上記の方法で施工図面を完了したら、それは単一のソースへの最長パスを見つけるために、再びdijsktra実行とばかり仮想出発点光源です。
コードで
//1613829 <13100928923> <王恪楠> 再卖菜 11-21 21:22 1.678KB C0X 正确 100 15ms 576.0KB
#include <bits/stdc++.h>
#define to first
#define coast second
using namespace std;
const int MAXN = 5e2;
typedef pair<int, int> P;
int a[MAXN], s[MAXN], d[MAXN], n;
vector<P> G[MAXN];
void add_edge(int u, int v, int w)
{
G[u].push_back(P(v, w));
return;
}
void dijsktra() //用dijsktra算法求最长路,把最短路的写法反过来写.
{
priority_queue<P> q;
d[0] = 0;
q.push(P(0, 0));
while(!q.empty()){
P p = q.top();
q.pop();
int v = p.second;
if(d[v] > p.first) continue;
for(int i = 0; i < G[v].size(); i ++){
P e = G[v][i];
if(d[e.to] < d[v] + e.coast){
d[e.to] = d[v] + e.coast;
q.push(P(d[e.to], e.to));
}
}
}
return;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
//加边建图.
for(int i = 2; i < n; i ++){
add_edge(i - 2, i + 1, 3 * a[i]);
add_edge(i + 1, i - 2, -3 * a[i] - 2);
}
add_edge(0, 2, 2 * a[1]);
add_edge(2, 0, -2 * a[1] - 1);
add_edge(n - 2, n, 2 * a[n]);
add_edge(n, n - 2, -2 * a[n] - 1);
for(int i = 1; i <= n; i ++)
add_edge(i - 1, i, 1);
dijsktra(); //跑一遍dijsktra.
for(int i = 1; i <= n; i ++)
printf("%d ", d[i] - d[i - 1]); //d[i]是前缀和数组.
return 0;
}