【第二学期第四周学习记录】

P1164 小A点菜

题目背景

uim 神犇拿到了 uoi 的 ra(镭牌)后,立刻拉着基友小 A 到了一家……餐馆,很低端的那种。

uim 指着墙上的价目表(太低级了没有菜单),说:“随便点”。

题目描述

不过 uim 由于买了一些书,口袋里只剩 M M M ( M ≤ 10000 ) (M \le 10000) (M10000)

餐馆虽低端,但是菜品种类不少,有 N N N ( N ≤ 100 ) (N \le 100) (N100),第 i i i 种卖 a i a_i ai ( a i ≤ 1000 ) (a_i \le 1000) (ai1000)。由于是很低端的餐馆,所以每种菜只有一份。

小 A 奉行“不把钱吃光不罢休”的原则,所以他点单一定刚好把 uim 身上所有钱花完。他想知道有多少种点菜方法。

由于小 A 肚子太饿,所以最多只能等待 1 1 1 秒。

输入格式

第一行是两个数字,表示 N N N M M M

第二行起 N N N 个正数 a i a_i ai(可以有相同的数字,每个数字均在 1000 1000 1000 以内)。

输出格式

一个正整数,表示点菜方案数,保证答案的范围在 int 之内。

输入输出样例 #1

输入 #1

4 4
1 1 2 2

输出 #1

3

说明/提示

2020.8.29,增添一组 hack 数据 by @yummy

思路

这是一道非常典型的背包dp求方案数()
所以我们直接套板子就好了QAQ()

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long

const int N=1e4+3;
int f[N],v[N];

signed main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>v[i];
	}
	f[0]=1;
	for(int i=1;i<=n;i++){
		for(int j=m;j>=v[i];j--){
			f[j]+=f[j-v[i]];
		}
	}
	cout<<f[m];
	return 0;
} 

AT_abc330_c [ABC330C] Minimize Abs 2

题目描述

正整数 $ D $ が与えられます。

非負整数 $ x,y $ に対する $ |x2+y2-D| $ の最小値を求めてください。

输入格式

入力は以下の形式で標準入力から与えられる。

$ D $

输出格式

答えを出力せよ。

输入输出样例 #1

输入 #1

21

输出 #1

1

输入输出样例 #2

输入 #2

998244353

输出 #2

0

输入输出样例 #3

输入 #3

264428617

输出 #3

32

说明/提示

制約

  • $ 1\leq\ D\ \leq\ 2\times\ 10^{12} $
  • 入力は全て整数

Sample Explanation 1

$ x=4,y=2 $ のとき $ |x2+y2-D|\ =\ |16+4-21|=1 $ となります。 $ |x2+y2-D|=0 $ を満たすような非負整数 $ x,y $ は存在しないので、答えは $ 1 $ です。

思路

  • 先从一开始,一个数一个数往上找,知道有一个数的平方超过这个数时停止;
  • 否则一直循环去找最小值;

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long

signed main()
{
	int d;
	cin>>d;
	int mm=1e12+11;
	for(int i=1;i<=1e7+10;i++){
		if(i*i>d)	break;
		int l=d-i*i;
		int j=sqrt(l);
		int t=min(abs(i*i+j*j-d),abs(i*i-d+(j+1)*(j+1)));
		mm=min(mm,t);
	}
	cout<<mm;
	return 0;
}

AT_abc330_d [ABC330D] Counting Ls

题目描述

$ N\ \times\ N $ のマス目が与えられます。このうち上から $ i $ 行目、左から $ j $ 列目のマスを $ (i,j) $ と書きます。
各マスの状態を表す $ N $ 個の長さ $ N $ の文字列 $ S_1,S_2,\dots,S_N $ が以下の形式で与えられます。

  • $ S_i $ の $ j $ 文字目が o であるとき、 $ (i,j) $ には o が書かれている。
  • $ S_i $ の $ j $ 文字目が x であるとき、 $ (i,j) $ には x が書かれている。

以下の条件を全て満たすマスの三つ組の個数を求めてください。

  • 組に含まれる $ 3 $ マスは相異なる。
  • $ 3 $ マス全てに o が書かれている。
  • マスのうち、丁度 $ 2 $ つが同じ行にある。
  • マスのうち、丁度 $ 2 $ つが同じ列にある。

但し、ふたつの三つ組は、丁度一方に含まれるマスが存在する場合のみ区別します。

输入格式

入力は以下の形式で標準入力から与えられる。

$ N $ $ S_1 $ $ S_2 $ $ \vdots $ $ S_N $

输出格式

答えを整数として出力せよ。

输入输出样例 #1

输入 #1

3
ooo
oxx
xxo

输出 #1

4

输入输出样例 #2

输入 #2

4
oxxx
xoxx
xxox
xxxo

输出 #2

0

输入输出样例 #3

输入 #3

15
xooxxooooxxxoox
oxxoxoxxxoxoxxo
oxxoxoxxxoxoxxx
ooooxooooxxoxxx
oxxoxoxxxoxoxxx
oxxoxoxxxoxoxxo
oxxoxooooxxxoox
xxxxxxxxxxxxxxx
xooxxxooxxxooox
oxxoxoxxoxoxxxo
xxxoxxxxoxoxxoo
xooxxxooxxoxoxo
xxxoxxxxoxooxxo
oxxoxoxxoxoxxxo
xooxxxooxxxooox

输出 #3

2960

说明/提示

制約

  • $ N $ は $ 2 $ 以上 $ 2000 $ 以下の整数
  • $ S_i $ は長さ $ N $ の ox からなる文字列

Sample Explanation 1

以下の $ 4 $ つの三つ組が条件を満たします。 - $ (1,1),(1,2),(2,1) $ - $ (1,1),(1,3),(2,1) $ - $ (1,1),(1,3),(3,3) $ - $ (1,2),(1,3),(3,3) $

思路

  • 先把每个点读进来,并找到每行每列有多少个o;
  • 之后找到那个可以共用的点,如果这个点所在的行和列都不是仅他一个点,就可以计算了;

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long

char a[2002][2002];
int r[2002],c[2002];
signed main()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		string s;
		cin>>s;
		for(int j=0;j<s.size();j++){
			a[i][j+1]=s[j];
			if(a[i][j+1]=='o'){
				r[i]++;c[j+1]++;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]=='o'&&r[i]>=2&&c[j]>=2){
				ans+=(r[i]-1)*(c[j]-1);
			}
		}
	}
	cout<<ans;
	return 0;
}

P8605 [蓝桥杯 2013 国 AC] 网络寻路

题目描述

X X X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包,为了安全起见,必须恰好被转发两次到达目的地。该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径。

源地址和目标地址可以相同,但中间节点必须不同。

如图 1 1 1 所示的网络。

1 → 2 → 3 → 1 1 \to 2 \to 3 \to 1 1231 是允许的。

1 → 2 → 1 → 2 1 \to 2 \to 1 \to 2 1212 或者 1 → 2 → 3 → 2 1 \to 2 \to 3 \to 2 1232 都是非法的。

输入格式

输入数据的第一行为两个整数 N , M N,M N,M,分别表示节点个数和连接线路的条数 ( 1 ≤ N ≤ 10000 , 0 ≤ M ≤ 100000 ) (1 \le N \le 10000,0 \le M \le 100000) (1N10000,0M100000)

接下去有 M M M 行,每行为两个整数 u u u v v v,表示节点 u u u v v v 联通 ( 1 ≤ u , v ≤ N , u ≠ v ) (1 \le u,v \le N,u \neq v) (1u,vN,u=v)

输入数据保证任意两点最多只有一条边连接,并且没有自己连自己的边,即不存在重边和自环。

输出格式

输出一个整数,表示满足要求的路径条数。

输入输出样例 #1

输入 #1

3 3
1 2
2 3
1 3

输出 #1

6

输入输出样例 #2

输入 #2

4 4
1 2
2 3
3 1
1 4

输出 #2

10

说明/提示

时限 1 秒,空间限制 64M。蓝桥杯 2013 年第四届国赛


2024/1/28 添加一组 hack 数据

思路

  • 好神奇的一道题,我开始以为要用dfs,但dfs会超时;
  • 探索发现其实不用:如果已知一条路存在,只用找以这条路作为中间路段的路一共有多少条就好;最后再把所有一直路线可延申出的道路条数相加即可;

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N=1e5+12;
int n,m;
vector<int> e[N];
int x[N],y[N];
signed main()
{
	cin>>n>>m;
	int ans=0;
	for(int i=1;i<=m;i++){
		cin>>x[i]>>y[i];
		e[x[i]].push_back(y[i]);
		e[y[i]].push_back(x[i]);
	}
	for(int i=1;i<=m;i++){
		ans+=(e[x[i]].size()-1)*(e[y[i]].size()-1);
	}
	cout<<ans*2;
	return 0;
}

P8686 [蓝桥杯 2019 省 A] 修改数组

题目描述

给定一个长度为 N N N 的数组 A = [ A 1 , A 2 , ⋯ A N ] A=[A_1,A_2, \cdots A_N] A=[A1,A2,AN],数组中有可能有重复出现的整数。

现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改 A 2 , A 3 , ⋯   , A N A_2,A_3, \cdots ,A_N A2,A3,,AN

当修改 A i A_i Ai 时,小明会检查 A i A_i Ai 是否在 A 1 A_1 A1 A i − 1 A_{i-1} Ai1 中出现过。如果出现过,则小明会给 A i A_i Ai 加上 1 1 1;如果新的 A i A_i Ai 仍在之前出现过,小明会持续给 A i A_i Ai 1 1 1,直到 A i A_i Ai 没有在 A 1 A_1 A1 A i − 1 A_{i-1} Ai1 中出现过。

A N A_N AN 也经过上述修改之后,显然 A A A 数组中就没有重复的整数了。

现在给定初始的 A A A 数组,请你计算出最终的 A A A 数组。

输入格式

第一行包含一个整数 N N N

第二行包含 N N N 个整数 A 1 , A 2 , ⋯   , A N A_1,A_2, \cdots ,A_N A1,A2,,AN

输出格式

输出 N N N 个整数,依次是最终的 A 1 , A 2 , ⋯   , A N A_1,A_2, \cdots ,A_N A1,A2,,AN

输入输出样例 #1

输入 #1

5
2 1 1 3 4

输出 #1

2 1 3 4 5

说明/提示

对于 80 % 80\% 80% 的评测用例, 1 ≤ N ≤ 10000 1 \le N \le 10000 1N10000

对于所有评测用例, 1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1N105 1 ≤ A i ≤ 1 0 6 1 \le A_i \le 10^6 1Ai106

蓝桥杯 2019 年省赛 A 组 H 题。

思路

  • 可以拿set做;
  • 先把题目范围内的所有数都存起来;如果出现就删去;每次找不小于该数的最小值输出;输出后就删去()

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long

set<int> s;
signed main()
{
	int n;cin>>n;
	for(int i=1;i<=1e6+1e5;i++){//
		s.insert(i);
	}
	for(int i=1;i<=n;i++){
		int a;cin>>a;
		auto f=s.lower_bound(a);
		s.erase(*f);
		cout<<*f<<" "; 
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值