sort(): greater();
upper_bound(), lower_bound(), binary_search();
vector: push_back(), pop_back(), swap(), clear(), insert() {O(n)};
pair: first, second, make_pair();
iterator: begin(), end();
map: insert(), count(), size(), erase(map::iterator), swap(), clear();
multimap: 可重集的map;
set, stack, queue, priority_queue
deque: front(), back(), push_front(), push_back(), pop_front(), pop_back(), at()
位运算:P2114 [NOI2014]起床困难综合症
题意:有 opt (0 \le t \le 10^9)$,初始攻击力
输入格式:
第
接下来
输出格式:
一个整数,表示最大攻击力。
逐位贪心,对
void work(int len,bool full) {
if(!len) return;
int up=full?bin[len]:1;
opt[0]=opt[1]=-1;
for(int i=0;i<=up;++i) opt[i]=solve(len,i);
ans+=max(opt[0],opt[1])*(1<<(len-1));
if(!full) work(len-1,false);
else work(len-1,bin[len]?(opt[1]>opt[0]):true);
}
work(len,1);
差分:P4552 [Poetize6] IncDec Sequence
$Problem: $ 给定一个长度为
请问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。
输入格式:
第一行一个正整数
输出格式:
第一行输出最少操作次数。 第二行输出最终能得到多少种结果。
原问题转化为:将差分数组中
每步操作分三种讨论:
- 选取一个**正数 (
$c_x$ ) 和一个负数 ($c_y$ ) **,使正数减1,负数加1,这样经过N次操作,我们一定可以以最少的代价将绝对值较小的一方归零,代价为$$abs(min(X,Y))$$ - 选取一个正数 (
$c_x$ ),使其与 a[1] 配对,这样,我们经过N次操作,一定可以将它归零,代价为:$$abs(X)$$ - 选取一个负数 (
$c_y$ ),使其与 a[n+1] 配对,这样,我们经过N次操作,一定可以将它归零,代价为:$$abs(Y)$$
最小步数应该优先选第1种操作,再选2、3种方案
则
第二种操作后共有$abs(X-Y)+1$种可能,于是
维护一个数列
-
1 l r K D
:给出一个长度等于$r-l+1$ 的等差数列,首项为$K$ ,公差为$D$ ,并将它对应加到$[l,r]$ 范围中的每一个数上。即:令 $a_l=a_l+K,a_{l+1}=a_{l+1}+K+D,\ldots~,~a_r=a_r+K+(r-l) \times D$。 -
2 p
:询问序列的第$p$ 个数的值$a_p$ 。
输入格式:
第一行两个整数
第二行
接下来的
若
若
输出格式:
对于每个询问,一行一个整数表示答案。
考虑差分,用线段树维护从
-
修改
$a_l$ 到$a_r$ 时,令$c_l=c_l+k,~c_i=c_i+d(l+1 \le i \le r),~c_{r+1}=c_{r+1}-k-(r-l+1) \times d$ -
单点查询
$a_k$ ,输出$\sum_{i=1}^k c_i$ 即可。
scanf("%d",&op);
if(op==1){
scanf("%d%d%d%d",&x,&y,&k,&d);
add(1,x,x,k);
if(y>x) add(1,x+1,y,d);
if(y+1<=n) add(1,y+1,y+1,-1ll*d*(y-x)-k);
}else if(op==2){
scanf("%d",&x);
printf("%lld\n",query(1,1,x));
树上差分:P3128 [USACO15DEC]Max Flow P
Farmer John给他的牛棚的
对每条路径的起点
从根节点开始深搜,回溯时将其本身的权值加上所有子节点的权值。
每个节点的权值也是其被路径覆盖的次数。
已知路径求被所有路径覆盖的边
首先对已知的这
从根节点开始深搜,回溯时将其本身的权值加上所有子节点的权值。
那么满足要求的边就是权值等于
**Hash表:**利用Hash函数计算出哈希值,插入到对应的邻接表处。
有
第
因为雪花的形状是封闭的环形,所以从任何一个角开始顺时针或逆时针往后记录长度,得到的六元组都代表形状相同的雪花。
例如
我们称两片雪花形状相同,当且仅当它们各自从某一角开始顺时针或逆时针记录长度,能得到两个相同的六元组。
求这N片雪花中是否存在两片形状相同的雪花。
输入格式:
第一行输入一个整数
接下来
每行包含
输出格式:
如果不存在两片形状相同的雪花,则输出:No two snowflakes are alike.
如果存在两片形状相同的雪花,则输出:Twin snowflakes found.
数据范围:
Hash:
P6739 [BalticOI 2014 Day1] Three Friends
有一个字符串
- 将
$S$ 复制为两份,存在字符串$T$ 中 - 在
$T$ 的某一位置上插入一个字符,得到字符串$U$ 现在给定$U$ ,求$S$ 。
输出格式:
- 如果不能通过上述的步骤从
$S$ 推到$U$ ,输出NOT POSSIBLE
。 - 如果从
$U$ 得到的$S$ 不是唯一的,输出NOT UNIQUE
。 - 否则,输出一个字符串
$S$ 。
字符串Hash:
const int maxn=2e6+10,base=233;
int n;
int h[maxn]; //从1到i的哈希值
int p[maxn]; //base的i次方
char s[maxn]; //修改后的字符串
//获取删去第k的个字符后的哈希值
int getdel(int k){return h[k-1]*p[n-k]+(h[n]-h[k]*p[n-k]);}
int main(){
scanf("%d%s",&n,s+1);
if(n%2==0) {puts("NOT POSSIBLE");return 0;} //长度为奇数不存在
p[0]=1; h[0]=0;
for(int i=1;i<=n;i++) p[i]=p[i-1]*base;
for(int i=1;i<=n;i++) h[i]=h[i-1]*base+s[i];
bool found=false;
int fdidx; //删除第fdidx个字符满足条件
char ans[maxn]="";
int mid=n/2;
for(int i=1;i<=n;i++){
int right=getdel(i),cur;
if(i<=mid) cur=h[n]-h[n-mid]*p[mid];
else cur=h[mid];
if(cur*(p[mid]+1)==right){ //找到符合条件的串
if(!found){
found=true;
fdidx=i;
int cnt=1;
for(int j=1;cnt<=mid;j++)
if(i!=j) ans[cnt++]=s[j];
}else if(getdel(fdidx)!=getdel(i)){ //原串不唯一
puts("NOT UNIQUE");
return 0;
}
}
}
if(!found) puts("NOT POSSIBLE");
else printf("%s\n",ans+1);
return 0;
}
**A*算法:**类似
将结点按照
一道红题:Acwing178. 第K短路
-1
。
输入格式:
第一行包含两个整数
接下来
最后一行包含三个整数
- 最短路求出每个点到终点的距离
- A* 爆搜,估价函数定为该节点到终点的最短路长度。每次从优先队列中取出
$dis(x)+h(x)$ 最小的结点。当第$k$ 次取出终点时,该路径即为第$k$ 短路。
void A_star(){
if(dis[S]==dis[0]){puts("-1");return;}
memset(vis,0,sizeof(vis));
q.push(make_pair(dis[S],S));
while(q.size()){
int x=q.top().second,d=q.top().first+dis[x];
q.pop(); vis[x]++;
if(vis[T]==K) {printf("%d\n",d);return;}
for(int i=head[x];i;i=e[i].next){
int y=e[i].y;
if(vis[y]!=K)q.push(make_pair(d+e[i].to+dis[y],y));
}
}
puts("-1");
}
迭代加深:
UVA12558 埃及分数 Egyptian Fractions (HARD version)
- 给定一个分数
$\dfrac{a}{b}$ ,然后给定$k$ 个数$q_i$ 。 - 要求把
$\dfrac{a}{b}$ 分为几个不同的分子为$1$ 的最简分数,要求分成的分数的分母中不能出现$q_i$ 。 - 若有多种情况,输出拆分出分数最少的一种。
- 如果还有多种情况,应使第一大的分母最小,如果还不行,第二大最小,以此类推。
-
本题有
$t$ 组数据,$t \le 100$ 。 - 其他数据范围:$2 \le a, b \le 876$,$0 \le k \le 5$,$\gcd(a,b)=1$,$2 \le q_i \le 1000$。
int main(){
read(n),read(m);
for(int i=1;i<=n;i++) read(a[i]),f[i][0]=a[i];
for(int i=1;(1<<i)<=n;i++){ //枚举区间
for(int j=1;j+(1<<i)-1<=n;j++) //枚举起点
f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]);
}
for(int i=1,l,r;i<=m;i++){
read(l),read(r);
int k=log2(r-l+1); //中间值
write(max(f[l][k],f[r-(1<<k)+1][k]));
}
return 0;
}
二维ST表:P2216 [HAOI2007]理想的正方形
有一个
输入格式:
第一行为
第二行至第
输出格式:
仅一个整数,为
for(int k=1;k<=log2(min(n,m));k++)
for(int i=1;i+(1<<k)-1<=n;i++)
for(int j=1;j+(1<<k)-1<=m;j++)
st[i][j][k]=max(max(max(st[i][j][k-1],st[i+(1<<(k-1))][j][k-1]),st[i][j+(1<<(k-1))][k-1]),st[i+(1<<(k-1))][j+(1<<(k-1))][k-1]);
for(int k=1;k<=log2(min(n,m));k++)
for(int i=1;i+(1<<k)-1<=n;i++)
for(int j=1;j+(1<<k)-1<=m;j++)
st1[i][j][k]=min(min(min(st1[i][j][k-1],st1[i+(1<<(k-1))][j][k-1]),st1[i][j+(1<<(k-1))][k-1]),st1[i+(1<<(k-1))][j+(1<<(k-1))][k-1]);
在艾泽拉斯,有
城市之间有
每次经过一个城市,都会被收取一定的过路费(包括起点和终点)。路上并没有收费站。
假设
歪嘴哦不希望花很多钱,他想知道,在可以到达奥格瑞玛的情况下,他所经过的所有城市中最多的一次收取的费用的最小值是多少。
输入格式:
第一行3个正整数,$n,m,b$。分别表示有
接下来有
再接下来有
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
int n,m,b,fee[10001],head[10001],cnt,dis[10001],v[10001];
struct Edge{
int to;
int val;
int nxt;
}a[200001];
priority_queue<int,vector<int>,greater<int> > q;
void add(int x,int y,int z);
bool check(int x);
int main(){
ios::sync_with_stdio(false);
int l=0,r=0,mid;
cin>>n>>m>>b;
for(int i=1;i<=n;i++){
cin>>fee[i];
r=max(r,fee[i]);
}
for(int i=1,x,y,z;i<=m;i++){
cin>>x>>y>>z;
if(x==y) continue;
add(x,y,z);
add(y,x,z);
}
if(!check(r+1)){
cout<<"AFK"<<endl;
return 0;
}
l=max(fee[1],fee[n]);
while(l<=r){
mid=l+r>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
cout<<l<<endl;
}
void add(int x,int y,int z){
a[++cnt].to=y;
a[cnt].val=z;
a[cnt].nxt=head[x];
head[x]=cnt;
return;
}
bool check(int x){
if(x<fee[1]||x<fee[n]) return false;
for(int i=1;i<=n;i++){
if(fee[i]>x) v[i]=true;
else v[i]=false;
}
for(int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;
//memset(dis,0x3f,sizeof(dis));
dis[1]=0;
v[1]=true;
q.push(1);
while(!q.empty()){
int cur=q.top();
q.pop();
for(int i=head[cur];i;i=a[i].nxt){
if(dis[a[i].to]>dis[cur]+a[i].val){
dis[a[i].to]=dis[cur]+a[i].val;
if(!v[a[i].to]) q.push(a[i].to);
}
}
}
if(dis[n]>b) return false;
return true;
}