搜索
DFS与BFS
-
- bfs:求最小量,不会爆栈
- 走地图flood fill
最短路
多源bfs
最小
树与图的遍历:拓扑排序
最短路
最小生成树
二分图:染色法、匈牙利算法
DP
数字三角行
矩阵(1,1)->(n,n),每一个节点或有不一样->求max/min
- 摘花生
-
- 走矩阵,使路线上的节点花生数之和max
- max(从上继承 or 从右继承)+v
- 最低通行费
-
- 走网格不回头,使每通过一个格子的花费最少
- min(从上继承 or 从右继承)+v
- 方格取数
-
- 走两次=优化=同时走(一头一尾)因为第一次走的时候有可能有好几条路径都是第一次的解,而你分开走只能选择其中的一条。很不幸的是,第一次走过的地方会被重置成0,而你不确定的是第一次同样是最优解而未被你选择的情况下第二次的值会不会比你已经得出的答案要大。
- 三维;1:总的行的格子2*N,2:第一次;2:第二次
- 取“四个”方向的max(对于每一次有两个,不是东南西北,只有西南)
- max(从上继承 or 从右继承)+v
- 传纸条
-
- 和方格取数类似
最长上升子序列
- 怪盗基德的滑翔翼
-
- 因为题目要求一旦下降就不能回高,要尽量经过多的地方,所以要考虑往哪个方向走最多
- 那就走两边,一遍从左到右,一遍从右到左,求哪个的最长上升子序列最大,就从反面跑,取max
- 每一个点就是一个序列,长度为1;对于i,从0-i遍历,若前者小于当前,就继承,比较取max,否则重新开始
- 每一个点保存的是其他点到本点的最长上升子序列的长度
- 登山
-
- 对于每一个点,向左向右的最长上升子序列之和max
- 合唱队形
-
- 求整个队列中最长子最长
- 友好城市
-
- 一岸是索引,另一个是值,找到最大上升子序列即可
- 最大 ·的·上升子序列和
-
- 和是最大的
- 对于每一个数,只要可以继承前面的,就看加上这个数会不会比原来大就好
- 拦截导弹
-
- 问题一,可以拦截多少个:找最长
- 问题二,全部拦截需要多少个:找的过程中,只要不继承,ans++
for(int i = 0; i < n; i ++) { f[i] = 1; for(int j = 0; j < i; j ++) { if(a[i] <= a[j]) f[i] = max(f[i], f[j] + 1); } ans = max(ans, f[i]); //数组g的每个元素代表一套导弹拦截系统的拦截序列 //g[i]表示此时第i套导弹拦截系统所拦截的最后一个导弹的高度 int p = lower_bound(g, g+cnt, a[i]) - g; if(p == cnt) g[cnt ++] = a[i]; //a[i]开创一套新拦截系统 else g[p] = a[i]; //a[i]成为第p套拦截系统最后一个导弹高度 } 链接:https://www.acwing.com/solution/content/10173/
- 导弹防御系统
- 最长上升公共子序列
-
- dp思路:dp[i][j]:在a长度为i,b长度为j的位置,最长的序列长度,站在a的角度选b加入
- N^2,;f[i][j]=f[i-1][j];;当a[i]=b[j],找max(max,f[i-1][j]+1);
- 如果≠,;>:max(f[i-1][j]+1,amx);amx是目前最长的;
背包模型
- 采药
-
- 代价:t,价值:w;总容量:T,求w的max
- dp:对于每一个物品,max(f[j],f[j-t]+w)这就是选和不选(用了滚动数组)
for (int i = 0; i < n; i ++ ) { int v, w; cin >> v >> w; for (int j = m; j >= v; j -- ) f[j] = max(f[j], f[j - v] + w); } cout << f[m] << endl;//M是容量,这是倒序计算的,肯定满足条件
- 装箱问题
-
- 剩余容量最小,装得最多
- M-f[m]
- 宠物小精灵之收服
-
- 限制:体力,球数,目标:个数尽量多
- 二维变三维,是一样的,和那个折扣五维是一样的
- 数字组合
-
- 给定的是多少个不同的数值,没有限定个数,属于完全背包
- 有多少种选择方案就是f[m]的值,对于数组F,索引是代表着和
- 只要a小于它,它就一定能包含构成a的个数
- 买书
-
- 价格容量n元,各价值为各书价格
- 完全背包模型,只要价格少于n,就能包含它的方案
- 货币系统1
-
- n种面值,组成m的方案
- 货币系统2
- 多重背包问题
-
- 拆解为01背包
for (int i = 1; i <= n; ++ i) { for (int j = m; j >= v[i]; -- j) { for (int k = 0; k <= s[i]; ++ k) { if (j - k * v[i] >= 0) { f[j] = max(f[j], f[j - k * v[i]] + k * w[i]); } } } }
- 庆功会
-
- 一共m元,价值最大
- 多重背包
- 混合背包问题
-
- 01+完全+多重
-
-
- 完全背包:限制为最大件数
-
- 二维费用背包问题
-
- 限制V,M,使得价值最大
- 一维转二维
- 潜水员
第五章
筛法
哥德巴赫猜想
任意一个大于 44 的偶数都可以拆成两个奇素数之和。
例如:
8=3+58=3+5
20=3+17=7+1320=3+17=7+13
42=5+37=11+31=13+29=19+2342=5+37=11+31=13+29=19+23
现在,你的任务是验证所有小于一百万的偶数能否满足哥德巴赫猜想。
输入格式
输入包含多组数据。
每组数据占一行,包含一个偶数 nn。
读入以 00 结束。
输出格式
对于每组数据,输出形如 n = a + b
,其中 a,ba,b 是奇素数。
若有多组满足条件的 a,ba,b,输出 b−ab−a 最大的一组。
若无解,输出 Goldbach's conjecture is wrong.
。
数据范围
6≤n<1066≤n<106
输入样例:
8
20
42
0
输出样例:
8 = 3 + 5
20 = 3 + 17
42 = 5 + 37
#include<bits/stdc++.h>
using namespace std;
const int N =1000009;
bool v[N];int a[N],n,ans,cnt;
void pri(int n){/*欧拉筛板子*/
v[1]=1;/*特例,自己写的时候忘记了*/
for(int i=2;i<=n;i++){
if(!v[i])a[cnt++]=i;
for(int j=0;a[j]*i<=n;j++){
v[i*a[j]]=1;
if(i%a[j]==0)break;/*只能由最小筛去*/
}
}
}
int main(){
pri(N);
//for(int i=0;i<100;i++)cout<<a[i]<<" ";
while(cin>>n&&n){
int i=1;
while(i)
{
if(!v[n-a[i]]){/*减去质数后的数是不是质数*/
printf("%d = %d + %d\n",n,a[i],n-a[i]);
break;
}
i++;
}
}
}
1293. 夏洛克和他的女朋友
夏洛克有了一个新女友(这太不像他了!)。
情人节到了,他想送给女友一些珠宝当做礼物。
他买了 nn 件珠宝,第 ii 件的价值是 i+1i+1,也就是说,珠宝的价值分别为 2,3,…,n+12,3,…,n+1。
华生挑战夏洛克,让他给这些珠宝染色,使得一件珠宝的价格是另一件珠宝的价格的质因子时,两件珠宝的颜色不同。
并且,华生要求他使用的颜色数尽可能少。
请帮助夏洛克完成这个简单的任务。
输入格式
只有一行一个整数 nn,表示珠宝件数。
输出格式
第一行一个整数 kk,表示所使用的颜色数;
第二行 nn 个整数,表示第 11 到第 nn 件珠宝被染成的颜色。
若有多种答案,输出任意一种。
请用 11 到 kk 表示你用到的颜色。
数据范围
1≤n≤1051≤n≤105
输入样例1:
3
输出样例1:
2
1 1 2
输入样例2:
4
输出样例2:
2
2 1 1 2
#include<bits/stdc++.h>
using namespace std;
const int N =1e5+5;
bool v[N];int a[N],n,ans,cnt;
void pri(int n){
v[1]=1;
for(int i=2;i<=n;i++){
if(!v[i])a[cnt++]=i;
for(int j=0;a[j]*i<=n;j++){
v[i*a[j]]=1;
if(i%a[j]==0)break;
}
}
}
int main(){
cin>>n;
if(n==2 )cout<<"1\n1 1";
else if(n==1)cout<<"1\n1";/*特判*/
else{
pri(N);
cout<<"2\n";
for(int i=2;i<=n+1;i++){
if(!v[i])cout<<"1 ";
else cout<<"2 ";/*质数与质数互不相干,质数统一为同一个数,合数相区别于筛查自己的质数,不用管其他合数*/
}
}
}
196. 质数距离
给定两个整数 LL 和 UU,你需要在闭区间 [L,U][L,U] 内找到距离最接近的两个相邻质数 C1C1 和 C2C2(即 C2−C1C2−C1 是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。
同时,你还需要找到距离最远的两个相邻质数 D1D1 和 D2D2(即 D1−D2D1−D2 是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。
输入格式
每行输入两个整数 LL 和 UU,其中 LL 和 UU 的差值不会超过 106106。
输出格式
对于每个 LL 和 UU,输出一个结果,结果占一行。
结果包括距离最近的相邻质数对和距离最远的相邻质数对。(具体格式参照样例)
如果 LL 和 UU 之间不存在质数对,则输出 There are no adjacent primes.
。
数据范围
1≤L<U≤231−11≤L<U≤231−1
输入样例:
2 17
14 17
输出样例:
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
快速幂
1289. 序列的第k个数
BSNY 在学等差数列和等比数列,当已知前三项时,就可以知道是等差数列还是等比数列。
现在给你 整数 序列的前三项,这个序列要么是等差序列,要么是等比序列,你能求出第 kk 项的值吗。
如果第 kk 项的值太大,对其取模 200907200907。
输入格式
第一行一个整数 TT,表示有 TT 组测试数据;
对于每组测试数据,输入前三项 a,b,ca,b,c,然后输入 kk。
输出格式
对于每组数据,输出第 kk 项取模 200907200907 的值。
数据范围
1≤T≤1001≤T≤100,
1≤a≤b≤c≤1091≤a≤b≤c≤109,
1≤k≤1091≤k≤109
输入样例:
2
1 2 3 5
1 2 4 5
输出样例:
5
16
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+10;
ll a ,b,c,k,n;
ll qpow(ll a, ll b, ll c)
{
ll res = 1;
//a %= c;
while (b)
{
if (b & 1)
res = (res * a) % c;
a = (a * a) % c;
b >>= 1;
}
return res;
}
int main(){
int t;cin>>t;
while(t--){
cin>>a>>b>>c>>k;
if(2*b!=a+c){
cout<<(a*qpow(b/a,k-1,200907))%200907<<endl;;/*取模要仔细*/
}
else {
ll d=b-a;
cout<<(a+(k-1)*d)%200907<<endl;
}
}
return 0;
}
1290. 越狱
监狱有连续编号为 11 到 nn 的 nn 个房间,每个房间关押一个犯人。
有 mm 种宗教,每个犯人可能信仰其中一种。
如果相邻房间的犯人信仰的宗教相同,就可能发生越狱。
求有多少种状态可能发生越狱。
输入格式
共一行,包含两个整数 mm 和 nn。
输出格式
可能越狱的状态数,对 100003100003 取余。
数据范围
1≤m≤1081≤m≤108,
1≤n≤10121≤n≤1012
输入样例:
2 3
输出样例:
6
样例解释
所有可能的 66 种状态为:(000)(001)(011)(100)(110)(111)(000)(001)(011)(100)(110)(111)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+10;
ll a ,b,c,k,n;
ll qpow(ll a, ll b, ll c)
{
ll res = 1;
a %= c;
while (b)
{
if (b & 1)
res = (res * a) % c;
a = (a * a) % c;
b >>= 1;
}
return res;
}
int main(){
cin>>a>>b;
cout<<(100003+(qpow(a,b,100003)%100003-a*qpow(a-1,b-1,100003)%100003))%100003;/*取模....*/
return 0;
}
分解质因数
给定整数 NN,试把阶乘 N!N! 分解质因数,按照算术基本定理的形式输出分解结果中的 pipi 和 cici 即可。
输入格式
一个整数 NN。
输出格式
N!N! 分解质因数后的结果,共若干行,每行一对 pi,ci,表示含有 pici,pici 项。按照 pi 从小到大的顺序输出。
数据范围
3≤N≤1063≤N≤106
输入样例:
5
输出样例:
2 3
3 1
5 1
样例解释
5!=120=23∗3∗5
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+10;
ll a ,b,c,k,cnt,n;
bool v[N];
int p[N];
void pri(int n){
v[1]=1;
for(int i=2;i<=n;i++){
if(!v[i])p[cnt++]=i;
for(int j=0;i*p[j]<=n;j++){/*1-n中筛数*/
v[p[j]*i]=1;
if(i%p[j]==0)break;
}
}
}
int main(){
cin>>n;
pri(n);
for(int i=0;i<cnt;i++){/*从0开始*/
int s=0,t=p[i],ans=n;
while(ans){
s+=(ans/t);/*除以p,p^2,相当于1-n的都分解了*/
ans/=t;
}
cout<<t<<" "<<s<<endl;
}
return 0;
}