P1164 小A点菜
题目背景
uim 神犇拿到了 uoi 的 ra(镭牌)后,立刻拉着基友小 A 到了一家……餐馆,很低端的那种。
uim 指着墙上的价目表(太低级了没有菜单),说:“随便点”。
题目描述
不过 uim 由于买了一些书,口袋里只剩 M M M 元 ( M ≤ 10000 ) (M \le 10000) (M≤10000)。
餐馆虽低端,但是菜品种类不少,有 N N N 种 ( N ≤ 100 ) (N \le 100) (N≤100),第 i i i 种卖 a i a_i ai 元 ( a i ≤ 1000 ) (a_i \le 1000) (ai≤1000)。由于是很低端的餐馆,所以每种菜只有一份。
小 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 $ の
o
とx
からなる文字列
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 1→2→3→1 是允许的。
1 → 2 → 1 → 2 1 \to 2 \to 1 \to 2 1→2→1→2 或者 1 → 2 → 3 → 2 1 \to 2 \to 3 \to 2 1→2→3→2 都是非法的。
输入格式
输入数据的第一行为两个整数 N , M N,M N,M,分别表示节点个数和连接线路的条数 ( 1 ≤ N ≤ 10000 , 0 ≤ M ≤ 100000 ) (1 \le N \le 10000,0 \le M \le 100000) (1≤N≤10000,0≤M≤100000)。
接下去有 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) (1≤u,v≤N,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} Ai−1 中出现过。如果出现过,则小明会给 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} Ai−1 中出现过。
当 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 1≤N≤10000。
对于所有评测用例, 1 ≤ N ≤ 1 0 5 1 \le N \le 10^5 1≤N≤105, 1 ≤ A i ≤ 1 0 6 1 \le A_i \le 10^6 1≤Ai≤106。
蓝桥杯 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;
}