@ivorysi
2017-11-10T10:57:53.000000Z
字数 38177
阅读 858
复习
字符串的操作也有一些说道吧……毕竟……总忘
C类型的字符串,即char数组
从1开始存会更加方便
一定要#include!这是一个很有用的头文件!memset也在里面
char s[10000];scanf("%s",s+1);
如果读含有空格的字符串呢……我们可以选择getchar一个个扫进来,还有一个(在字符串空间足够的情况下)gets可以解决这个问题
char s[1005];int main() {gets(s+1);printf("%s\n",s+1);}
strlen(char *s);
char *s="RANK 1";int main() {printf("%d\n",strlen(s));}
输出
6
strcpy(char *destin,char *source) 将第二个字符复制到第一个字符串
strncpy(char *destin,char *source,int n) 将第二个字符串的前n个字符复制给第一个
char to[1005],*from="sigongzi is green sun";int main() {strncpy(to+1,from,8);printf("%s\n",to+1);strcpy(to+1,from);printf("%s\n",to+1);}
输出:
sigongzisigongzi is green sun
strcmp(char *s1,char *s2)
返回值为0时两字符串相等,否则返回第一个不相同的位置ASCII码的差值
char *s1="sigongzi",*s2="zigongsi",*s3="sigongzi";int main() {printf("%d\n",strcmp(s1,s2));printf("%d\n",strcmp(s2,s1));printf("%d\n",strcmp(s1,s3));}
输出
-770
有两个个很妙的操作叫sprintf和sscanf
char *s1="4711";int x;int main() {sscanf(s1,"%d",&x);printf("%d\n",x);}
char s[1005];int x=4711;int main() {sprintf(s,"%d",x);printf("%s\n",s);}
这两个的输出都是
4711
这也是一个很方便的类型
它的链接操作可以直接用+完成
比较可以用>、<、==
两个字符串之间的赋值可以用s1=s2完成
获得长度可以用s.length()
询问某个字符可以直接用数组的方式s[i]询问
s.insert(pos,s2)
是在pos前面插入s2这个串
s.substr(pos,n)
返回下标pos起长度为n的子串
s.erase(pos,n)
删除pos起的n个字符
s.replace(pos,n,s2)
将pos起n个字符替换成s2的内容
s.find(s2,pos)
查找pos起s2第一次出现的位置
返回一个c语言风格的指针,即char*
memset……这个太熟了
memcpy(dest,source,n);
int a[4]={4,7,1,1};int b[4];int main() {memcpy(b,a,sizeof(a));siji(i,0,3) {printf("%d ",b[i]);}}
输出
4711
front() 队首元素
pop() 弹出
push() 放进去
empty() 是否为空
push() 放进去
pop() 弹出来
top() 栈顶元素
empty() 是否为空
查找元素是否被建立过是
count()
插入可以像数组一样插入,询问可以像数组一样询问
注意multiset删除的时候删除某个特定元素需要用迭代器
find()查找
erase()删除
insert()插入
一个begin()指针是真实存在的,另一个end()作为结束标记是悬空的,不能访问
一般就是push_back()和pop_back()
int a[11]={1,2,3,4,5,6,7,7,7,7,8};int main() {int pos1=lower_bound(a,a+11,7)-a;int pos2=upper_bound(a,a+11,7)-a;printf("%d %d\n",pos1,pos2);}
输出
6 10
也就是说lower_bound是大于等于某个数的第一个
upper_bound是大于某个数的第一个
这大概应该是从入门就接触的第一个算法,也是将旷日持久陪伴我们的算法……这个算法的原理在小学就学过了……可惜细节太多了,唯一的办法就是多写了,鉴于noip考的算法不可能考裸的高精,一般的dp只涉及乘法和加法……那么板子先放在这里了
#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)//#define ivorysiusing namespace std;typedef long long ll;const int BASE=100000000;const int WIDTH=8;struct bignum {vector<int> v;bignum operator = (long long num) {v.clear();do{v.push_back(num%BASE);num/=BASE;}while(num>0);return *this;}bignum operator = (const string &str) {v.clear();int len=(str.length()-1)/WIDTH+1,x;xiaosiji(i,0,len) {int end=str.length()-i*WIDTH;int st=max(0,end-WIDTH);sscanf(str.substr(st,end-st).c_str(),"%d",&x);v.push_back(x);}return *this;}bignum operator + (const bignum &b) {int lena=v.size(),lenb=b.v.size();bignum c;c.v.clear();int p=0,g=0,x;while(1) {x=g;if(p<lena) x+=v[p];if(p<lenb) x+=b.v[p];if(p>=lena && p>=lenb && x==0) {break;}c.v.push_back(x%BASE);g=x/BASE;++p;}return c;}bignum operator *(const bignum &b) {int lena=v.size(),lenb=b.v.size();bignum c;c.v.clear();siji(i,0,lena+lenb) c.v.push_back(0);xiaosiji(i,0,lena) {ll g=0;xiaosiji(j,0,lenb) {ll x=(ll)v[i]*b.v[j]+g+c.v[i+j];c.v[i+j]=x%BASE;g=x/BASE;}int t=i+lenb;while(g) {ll x=g+c.v[t];c.v[t]=x%BASE;g=x/BASE;++t;}}int s=c.v.size();gongzi(i,s-1,1) {if(c.v[i]==0) {c.v.pop_back();}else break;}return c;}void out() {int s=v.size()-1;printf("%d",v[s]);--s;gongzi(i,s,0) {printf("%08d",v[i]);}putchar('\n');}}a,b;string stra,strb;int main() {cin>>stra>>strb;a=stra;b=strb;bignum t=a*b;t.out();}
这个名字看的我很眼熟,但我的确是很久没写了
noip2013火柴排队
#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define pii pair<int,int>#define fi first#define se second#define mod 99999997//#define ivorysiusing namespace std;typedef long long ll;int read() {int res=0;char c=getchar();while(c<'0' || c>'9') c=getchar();while(c>='0' && c<='9') {res=res*10-'0'+c;c=getchar();}return res;}pii a[1000005],b[1000005];int n;int c[1000005],num[1000005];ll ans;void merge(int l,int m,int r) {int pa=l,pb=m+1,p=l;while(pa<=m && pb<=r) {if(c[pa]<c[pb]) {num[p++]=c[pa++];}else {num[p++]=c[pb++];ans+=(m-pa+1);ans%=mod;}}while(pa<=m) {num[p++]=c[pa++];}while(pb<=r) {num[p++]=c[pb++];}siji(i,l,r) c[i]=num[i];}void mergesort(int l,int r) {if(l<r) {int m=(l+r)>>1;mergesort(l,m);mergesort(m+1,r);merge(l,m,r);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifn=read();siji(i,1,n) {a[i].fi=read();a[i].se=i;}siji(i,1,n) {b[i].fi=read();b[i].se=i;}sort(a+1,a+n+1);sort(b+1,b+n+1);siji(i,1,n) {c[a[i].se]=b[i].se;}mergesort(1,n);printf("%lld\n",ans);}
虽然应该归类到数据结构,但是都是求逆序对,就放一起了
noip2013火柴排队
#include <iostream>#include <cstdio>#include <algorithm>#include <vector>#include <cstring>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define pii pair<int,int>#define fi first#define se second#define mod 99999997//#define ivorysiusing namespace std;typedef long long ll;int read() {int res=0;char c=getchar();while(c<'0' || c>'9') c=getchar();while(c>='0' && c<='9') {res=res*10-'0'+c;c=getchar();}return res;}pii a[1000005],b[1000005];int n;int c[1000005];ll ans;int tr[1000005];int lowbit(int x){return x&(-x);}void change(int pos) {while(pos<=n) {++tr[pos];pos+=lowbit(pos);}}int query(int pos) {int res=0;while(pos>0) {res+=tr[pos];pos-=lowbit(pos);}return res;}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifn=read();siji(i,1,n) {a[i].fi=read();a[i].se=i;}siji(i,1,n) {b[i].fi=read();b[i].se=i;}sort(a+1,a+n+1);sort(b+1,b+n+1);siji(i,1,n) {c[a[i].se]=b[i].se;}siji(i,1,n) {ans+=query(n)-query(c[i]-1);change(c[i]);ans%=mod;}printf("%lld\n",ans);}
导弹拦截
我似乎已经很久没写过这个东西了
lower_bound 和upper_bound 真好用
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)//#define ivorysiusing namespace std;typedef long long ll;int n;int a[100005];int f[100005],cnt;void solve() {while(~scanf("%d",&a[++n]));--n;gongzi(i,n,1) {if(a[i]>=f[cnt]) {f[++cnt]=a[i];}else {int x=upper_bound(f,f+cnt,a[i])-f;if(a[i]<f[x]) f[x]=a[i];}}printf("%d\n",cnt);cnt=0;siji(i,1,n) {if(a[i]>f[cnt]) {f[++cnt]=a[i];}else {int x=lower_bound(f,f+cnt,a[i])-f;if(a[i]<f[x]) f[x]=a[i];}}printf("%d\n",cnt);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
ax+by=g的几个解
基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题
给出N个固定集合{1,N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数。
提示:
对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个。
第1行:1个整数T(1<=T<=50000),表示有多少组测试数据。
第2 - T+1行:每行三个整数N,A,B(1<=N,A,B<=2147483647)
对于每组测试数据输出一个数表示满足条件的集合的数量,占一行。
2
5 2 4
10 2 3
1
2
ax+by=n+1 看看n+1是不是g的倍数
如果是的话就从x的第一个解开始计算,每一个解的距离都是lcm(a,b)
如果第一个x是0的话就让x=b/g
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 100005//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0;char c=getchar();while(c < '0' || c > '9') c=getchar();while(c>='0' && c<='9') {res=res*10-'0'+c;c=getchar();}return res;}int gcd(ll a,ll b) {return b==0 ? a:gcd(b,a%b);}int ex_gcd(ll a,ll b,ll &x,ll &y) {if(b==0) {x=1;y=0;return a;}else {int res=ex_gcd(b,a%b,y,x);y-=a/b*x;return res;}}int t;ll n,a,b;void solve() {n=read();a=read();b=read();ll x=0,y=0;ll g=ex_gcd(a,b,x,y);x=((x%b)+b)%b;if((n+1)%g!=0) {puts("0");return;}else {x=(ll)x*((n+1)/g)%(b/g);if(x==0) x=b/g;if((ll)x*a>n) {puts("0");return;}int ans=(n-a*x)/((ll)a/g*b)+1;printf("%d\n",ans);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endift=read();while(t--) {solve();}}
暴力(violent)
时间:1s(如果用lemon评测,请开2s)
空间:64MB
如果认为本题正解有误或数据有误或正解不够优请通知我。
17.11.1:数据重新更新,如果仍有问题请通知我。
背景
XYC是未来OI的红太阳,今天就要参加2117 NOI professional,并打算ak全场。
但是很不幸,今年出2117 NOI professional的人是ZSW,他出了很多道大模拟题目,并伴随各种高深算法,很多学生纷纷爆零,走上了高考的不归路。
但是XYC可是未来的红太阳啊!就算题目很难,XYC神犇也不会爆零并且轻松RANK1啊,但是就算能够轻松省一,XYC还想要挑战自己的极限,得到尽可能高的分。
题面描述
本场2117 NOI professional的考试时间为TTT,共有NNN道题,当时间T<0T<0T<0时XYC就需要停止答题。
XYC初始的耐心值为WWW,当W<0W<0W<0,他就会厌倦去做这套题。
请注意做任何导致W<0W<0W<0和T<0T<0T<0的操作都是犯规的。
如果XYC下定决心要做某一道题,他就需要花费ttt的时间和www的耐心去读完题目。
当XYC读完题目后,XYC可以有三种选择且只能选择其中一种:
1. 写正解,XYC将花费tmaxtmaxtmax的时间和wmaxwmaxwmax的耐心并获得kmaxkmaxkmax的分数。
2. 写暴力,XYC有mmm种暴力可以写,每一个暴力需要花费tititi的时间和wiwiwi的耐心并获得kikiki的分数。每一道题每一种暴力只可以写一次,但XYC可以写多种暴力。
3. 写固输,XYC可以花费0的时间和0的耐心并获得1分。
请注意XYC一次只能做一件事(包括看题面,写正解,写一种暴力,写固输)。
XYC的目标是他得到的分数sumsumsum最大。
输入描述
第一行三个正整数NNN、TTT、WWW。
对于每一道题,其第一行为正整数ttt、www。
其第二行为三个正整数tmaxtmaxtmax、wmaxwmaxwmax、kmaxkmaxkmax。
其第三行为mmm。
其第四行到m+3m+3m+3行,每行三个正整数tititi、wiwiwi、kikiki。
输出描述
一行一个整数sumsumsum。
样例输入1
2 20 30
5 10
20 20 50
2
10 5 20
6 8 10
5 3
4 8 10
3
2 1 1
4 5 8
2 3 1
样例输出1
21
样例输入2
1 50 50
1 1
50 50 10000
0
样例输出2
1
数据规模
100%的数据满足,
N<=100N<=100N<=100,T<=50T<=50T<=50,W<=50W<=50W<=50,m<=40m<=40m<=40.
ki<=105ki<=10^5ki<=105,kmax<=107kmax<=10^7kmax<=107.
ttt,www,tmaxtmaxtmax,wmax<=100wmax<=100wmax<=100.
这道题很好
这道题的算法全名叫多维分组01背包……就是状态多了点,转移思路还是很简单的
适合练板子
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 100005//#define ivorysiusing namespace std;typedef long long ll;int n,m,T,W;ll vio[55][55],f[105][55][55],ans;ll t,w,tmax,kmax,wmax;ll tim[55],pat[55],val[55];int read() {int res=0;char c=getchar();while(c < '0' || c > '9') c=getchar();while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res;}void solve() {n=read();T=read();W=read();siji(i,1,n) {siji(j,0,T) {siji(l,0,W) {f[i][j][l]=max(f[i-1][j][l],f[i][j][l]);}}t=read();w=read();tmax=read();wmax=read();kmax=read();gongzi(j,T,t) {gongzi(l,W,w) {if(j>=tmax+t && l>=wmax+w)f[i][j][l]=max(f[i-1][j-tmax-t][l-wmax-w]+kmax,f[i][j][l]);f[i][j][l]=max(f[i-1][j-t][l-w]+1,f[i][j][l]);}}memset(vio,0,sizeof(vio));m=read();siji(k,1,m) {tim[k]=read();pat[k]=read();val[k]=read();gongzi(j,T,tim[k]) {gongzi(l,W,pat[k]) {vio[j][l]=max(vio[j][l],vio[j-tim[k]][l-pat[k]]+val[k]);}}}siji(ti,0,T) {siji(wi,0,W) {gongzi(j,T,ti+t) {gongzi(l,W,wi+w){f[i][j][l]=max(f[i-1][j-ti-t][l-wi-w]+vio[ti][wi],f[i][j][l]);}}}}}siji(j,0,T) {siji(l,0,W) {ans=max(ans,f[n][j][l]);}}printf("%lld\n",ans);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
板子……
注意一下根节点的deep是1
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 500005//#define ivorysiusing namespace std;typedef long long ll;int read() {int res=0;char c=getchar();while(c<'0' || c>'9') c=getchar();while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res;}struct node {int to,next;}edge[MAXN*2];int head[MAXN],sumedge;void add(int u,int v){edge[++sumedge].to=v;edge[sumedge].next=head[u];head[u]=sumedge;}void addtwo(int u,int v) {add(u,v);add(v,u);}int fa[MAXN][25],dep[MAXN];int n,m,s;void dfs(int u) {for(int i=head[u];i;i=edge[i].next) {int v=edge[i].to;if(v!=fa[u][0]) {fa[v][0]=u;dep[v]=dep[u]+1;dfs(v);}}}int lca(int a,int b) {if(dep[a]<dep[b]) swap(a,b);int l=20;while(dep[a]>dep[b]) {if(dep[fa[a][l]]>=dep[b]) {a=fa[a][l];}--l;}if(a==b) return a;l=20;while(fa[a][0]!=fa[b][0]) {if(fa[a][l]!=fa[b][l]) {a=fa[a][l];b=fa[b][l];}--l;}return fa[a][0];}void solve() {n=read();m=read();s=read();int x,y;xiaosiji(i,1,n) {x=read();y=read();addtwo(x,y);}dep[s]=1;dfs(s);siji(j,1,20) {siji(i,1,n) {fa[i][j]=fa[fa[i][j-1]][j-1];}}int a,b;siji(i,1,m) {a=read();b=read();int c=lca(a,b);printf("%d\n",c);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 500005//#define ivorysiusing namespace std;typedef long long ll;int read() {int res=0;char c=getchar();while(c<'0' || c>'9') c=getchar();while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res;}struct node {int to,next;}edge[MAXN*2];struct data {int to,next,lca;}qedge[MAXN*2];int head[MAXN],sumedge,qhead[MAXN],qsum=1,vis[MAXN],fa[MAXN];int n,m,s;void add(int u,int v){edge[++sumedge].to=v;edge[sumedge].next=head[u];head[u]=sumedge;}void qadd(int u,int v) {qedge[++qsum].to=v;qedge[qsum].next=qhead[u];qhead[u]=qsum;}void qaddtwo(int u,int v) {qadd(u,v);qadd(v,u);}void addtwo(int u,int v) {add(u,v);add(v,u);}int getfa(int x) {return fa[x]==x ? x:fa[x]=getfa(fa[x]);}void dfs(int u,int f) {for(int i=qhead[u];i;i=qedge[i].next) {int v=qedge[i].to;if(vis[v]) {qedge[i].lca=getfa(v);qedge[i^1].lca=getfa(v);}}vis[u]=1;for(int i=head[u];i;i=edge[i].next) {int v=edge[i].to;if(v!=f) {dfs(v,u);fa[getfa(v)]=getfa(u);}}}void solve() {n=read();m=read();s=read();int x,y;xiaosiji(i,1,n) {x=read();y=read();addtwo(x,y);}siji(i,1,m) {x=read();y=read();qaddtwo(x,y);}siji(i,1,n) {fa[i]=i;}dfs(s,0);siji(i,1,n) {printf("%d\n",qedge[i*2].lca);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
这道题还有求一条点值和最大的路径
要注意每个点的编号和每个点颜色编号的转换
颜色编号的降序其实就是缩点之后的拓扑序
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 10004#define MAXM 100005//#define ivorysiusing namespace std;typedef long long ll;int read() {int res=0;char c=getchar();while(c<'0' || c>'9') c=getchar();while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res;}struct node {int to,next;}edge[MAXM*2];int head[MAXN],sumedge;int n,m;void add(int u,int v){edge[++sumedge].to=v;edge[sumedge].next=head[u];head[u]=sumedge;}void addtwo(int u,int v) {add(u,v);add(v,u);}int col[MAXN],tot,instack[MAXN],dfn[MAXN],low[MAXN],cnt;int val[MAXN],sum[MAXN],dp[MAXN];vector<int> pos[MAXN];stack<int> s;void tarjan(int u) {instack[u]=1;dfn[u]=low[u]=++cnt;s.push(u);for(int i=head[u];i;i=edge[i].next) {int v=edge[i].to;if(!dfn[v]) {tarjan(v);low[u]=min(low[v],low[u]);}else if(instack[v]==1) {low[u]=min(dfn[v],low[u]);}}if(low[u]>=dfn[u]) {++tot;while(1) {int x=s.top();s.pop();pos[tot].push_back(x);instack[x]=2;col[x]=tot;if(x==u) break;}}}void solve() {n=read();m=read();int x,y;siji(i,1,n) {val[i]=read();}siji(i,1,m) {x=read();y=read();add(x,y);}siji(i,1,n) {if(!dfn[i]) {tarjan(i);}}siji(i,1,n) {sum[col[i]]+=val[i];}siji(i,1,tot) dp[i]+=sum[i];gongzi(i,tot,1) {int s=pos[i].size();xiaosiji(j,0,s) {int u=pos[i][j];for(int k=head[u];k;k=edge[k].next) {int t=edge[k].to;if(col[t]!=col[u]) {dp[col[t]]=max(sum[col[t]]+dp[col[u]],dp[col[t]]);}}}}int ans=0;siji(i,1,tot) {ans=max(ans,dp[i]);}printf("%d\n",ans);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
我……我发现我又忘了这玩意了
这个东西注意我们在走到搜索树的儿子边时要用儿子的low更新自身(和tarjan求强连通分量差不多),然后呢,这个点必须不是搜索树的根,然后再来判断这个点的某个儿子能不能走到这个点上面,如果不能说明这个点就是割点
注意判断这个东西不是搜索树的根!!!
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 10004#define MAXM 100005//#define ivorysiusing namespace std;typedef long long ll;int read() {int res=0;char c=getchar();while(c<'0' || c>'9') c=getchar();while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res;}struct node {int to,next;}edge[MAXM*2];int head[MAXN],sumedge;int n,m;void add(int u,int v){edge[++sumedge].to=v;edge[sumedge].next=head[u];head[u]=sumedge;}void addtwo(int u,int v) {add(u,v);add(v,u);}int dfn[MAXN],low[MAXN],cnt,ans;bool ispos[MAXN];void tarjan(int u,int fa) {dfn[u]=low[u]=++cnt;int son=0;for(int i=head[u];i;i=edge[i].next) {int v=edge[i].to;if(!dfn[v]) {tarjan(v,u);++son;low[u]=min(low[v],low[u]);if(fa!=0 && low[v]>=dfn[u]) {ispos[u]=1;}}else if(v!=fa){low[u]=min(dfn[v],low[u]);}}if(fa==0 && son>=2) {ispos[u]=1;}}void solve() {n=read();m=read();int x,y;siji(i,1,m) {x=read();y=read();addtwo(x,y);}siji(i,1,n) {if(!dfn[i]) {tarjan(i,0);}}siji(i,1,n) {if(ispos[i]) {++ans;}}printf("%d\n",ans);siji(i,1,n) {if(ispos[i]) {printf("%d ",i);}}puts("");}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
其实我是最近才会的,单个数逆元的求法就是普通的费马小定理快速幂
然后线性的有个递推式
siji(i,2,n) {inv[i]=(p-p/i)*inv[p%i]%p;}
证明设
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 3000005//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int n,p;ll inv[MAXN];void solve() {n=read();p=read();inv[1]=1;printf("%lld\n",inv[1]);siji(i,2,n) {inv[i]=(p-p/i)*inv[p%i]%p;printf("%lld\n",inv[i]);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
证明如下
中的系数
我们发现可以消掉一些系数然后式子就变成了……
能达到的情况只有i=t且j=q
所以
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 3000005//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int n,m,p,T;ll inv[MAXN],fac[MAXN];ll cnm(int y,int z) {return fac[y]*inv[z]%p*inv[y-z]%p;}ll fpow(ll x,int c) {ll res=1,t=x;while(c) {if(c&1) res=res*t%p;t=t*t%p;c>>=1;}return res;}ll Lucas(int y,int k) {int q,r;ll res=1;while(y>0 && k>0) {if(y<k) return 0;r=y%p;q=k%p;if(r<q) return 0;res=res*cnm(r,q)%p;y=y/p;k=k/p;}return res;}void solve() {n=read();m=read();p=read();fac[0]=1;siji(i,1,p-1) {fac[i]=fac[i-1]*i%p;}inv[p-1]=fpow(fac[p-1],p-2);gongzi(i,p-1,1) {inv[i-1]=inv[i]*i%p;}ll ans=Lucas(n+m,m);printf("%lld\n",ans);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifT=read();while(T--) {solve();}}
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 1000005//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}char s[MAXN],t[MAXN];int lens,lent;int next[MAXN];void solve() {scanf("%s%s",s+1,t+1);lens=strlen(s+1),lent=strlen(t+1);next[1]=0;siji(i,2,lent) {int p=next[i-1];while(p>0 && t[p+1]!=t[i]) p=next[p];if(t[p+1]==t[i]) next[i]=p+1;else next[i]=0;}int p=0;siji(i,1,lens) {while(p>0 && t[p+1]!=s[i]) p=next[p];if(t[p+1]==s[i]) ++p;if(p==lent) {p=next[p];printf("%d\n",i-lent+1);}}siji(i,1,lent) {printf("%d%c",next[i]," \n"[i==lent]);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
注意转移的时候是2×pos-i
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 25000005//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}char s[MAXN],t[MAXN*2];int r[MAXN*2];int lens,lent,ans;void solve() {scanf("%s",s+1);lens=strlen(s+1),lent=strlen(t+1);siji(i,1,lens) {t[i*2-1]='$';t[i*2]=s[i];}lent=lens*2+1;t[lent]='$';int pos=0,maxright=0;siji(i,1,lent) {r[i]=min(r[2*pos-i],maxright-i+1);r[i]=max(r[i],1);while(i+r[i]<=lent && i-r[i]>0 && t[i-r[i]]==t[i+r[i]]) ++r[i];if(i+r[i]-1>maxright) {maxright=i+r[i]-1;pos=i;}ans=max(ans,r[i]-1);}printf("%d\n",ans);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 10000005#define mod 1000000007//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int m,n;int prime[MAXN],cnt;bool isprime[MAXN];void solve() {n=read();m=read();memset(isprime,1,sizeof(isprime));isprime[1]=0;siji(i,2,n) {if(isprime[i]) {prime[++cnt]=i;}siji(j,1,cnt) {if(prime[j]>n/i) break;isprime[i*prime[j]]=0;if(i%prime[j]==0) break;}}int x;siji(i,1,m) {x=read();if(isprime[x]) {puts("Yes");}else {puts("No");}}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
假如是极大值,如果val(lm) < val(rm),那么极大值在[l,rm],否则极大值在[lm,r]
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 10000005#define mod 1000000007//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int n;double a[15],l,r;double val(double x) {double tmp=1.0,res=0.0;siji(i,1,n+1) {res+=tmp*a[i];tmp=tmp*x;}return res;}void solve() {scanf("%d%lf%lf",&n,&l,&r);siji(i,1,n+1) {scanf("%lf",&a[n-i+2]);}while(r-l>1e-6) {double lm=l+(r-l)/3.0;double rm=r-(r-l)/3.0;if(val(lm)<val(rm)) l=lm;else r=rm;}printf("%.5lf\n",l);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 10000005#define mod 1000000007//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int n,q;ll g[105][105];void solve() {n=read();siji(i,1,n) {siji(j,1,n) {g[i][j]=read();}}siji(k,1,n) {siji(i,1,n) {siji(j,1,n) {g[i][j]=min(g[i][k]+g[k][j],g[i][j]);}}}int a,b;q=read();siji(i,1,q) {a=read();b=read();printf("%lld\n",g[a][b]);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 10005#define MAXM 500005#define mod 1000000007#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int n,m,s;struct node {int to,next,val;}edge[MAXM*2];int head[MAXN],sumedge;void add(int u,int v,int c) {edge[++sumedge].to=v;edge[sumedge].next=head[u];edge[sumedge].val=c;head[u]=sumedge;}ll dis[MAXN],dist[MAXN];int tr[MAXN*4],pos[MAXN];bool vis[MAXN];void build(int u,int l,int r) {if(l==r) {tr[u]=l;pos[l]=u;return;}int m=(l+r)>>1;build(u<<1,l,m);build(u<<1|1,m+1,r);if(dist[tr[u<<1]]<dist[tr[u<<1|1]]) {tr[u]=tr[u<<1];}else {tr[u]=tr[u<<1|1];}}void change(int x) {int t=pos[x]>>1;while(t>=1) {if(dist[tr[t<<1]]<dist[tr[t<<1|1]]) {tr[t]=tr[t<<1];}else {tr[t]=tr[t<<1|1];}t>>=1;}}void dijkstra(int u) {siji(i,1,n) dist[i]=0x7fffffff;dist[u]=0;build(1,1,n);int cnt=n;while(cnt--) {int now=tr[1];dis[now]=dist[now];vis[now]=1;for(int i=head[now];i;i=edge[i].next) {int v=edge[i].to,w=edge[i].val;if((!vis[v]) && dist[v]-w>dist[now]) {dist[v]=dist[now]+w;change(v);}}dist[now]=(ll)0x7fffffff+1;change(now);}}void solve() {n=read();m=read();s=read();int a,b,c;siji(i,1,m) {a=read();b=read();c=read();add(a,b,c);}dijkstra(s);siji(i,1,n) {printf("%lld%c",dis[i]," \n"[i==n]);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXM 2000005#define mod 1000000007//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}struct node {int u,v,val;bool operator < (const node &b) {return val<b.val;}}edge[MAXM];int n,m;int fa[10005];int getfa(int x) {return x==fa[x]?x:fa[x]=getfa(fa[x]);}void solve() {n=read();m=read();int x,y,z;siji(i,1,m) {x=read();y=read();z=read();edge[i].u=x;edge[i].v=y;edge[i].val=z;}sort(edge+1,edge+m+1);siji(i,1,n) {fa[i]=i;}ll ans=0;siji(i,1,m) {int l=getfa(edge[i].u),z=getfa(edge[i].v);if(l!=z) {fa[l]=z;ans+=edge[i].val;}}printf("%lld\n",ans);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXM 2000005#define MAXN 10005#define mod 1000000007//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}struct node {int to,next,val;}edge[MAXM*4];int head[10005],sumedge;void add(int u,int v,int c) {edge[++sumedge].to=v;edge[sumedge].next=head[u];edge[sumedge].val=c;head[u]=sumedge;}bool vis[MAXN];int n,m,pos[MAXN];ll dist[MAXN],tr[MAXN*4],ans;void build(int u,int l,int r) {if(l==r) {tr[u]=l;pos[l]=u;return ;}int m=(l+r)>>1;build(u<<1,l,m);build(u<<1|1,m+1,r);if(dist[tr[u<<1]] < dist[tr[u<<1|1]]) {tr[u]=tr[u<<1];}else {tr[u]=tr[u<<1|1];}}void change(int x) {int t=pos[x]>>1;while(t>=1) {if(dist[tr[t<<1]]<dist[tr[t<<1|1]]) {tr[t]=tr[t<<1];}else {tr[t]=tr[t<<1|1];}t>>=1;}}void solve() {n=read();m=read();int x,y,z;siji(i,1,m) {x=read();y=read();z=read();add(x,y,z);add(y,x,z);}siji(i,1,n) dist[i]=0x7fffffff;dist[1]=0;build(1,1,n);int cnt=n;while(cnt--) {int u=tr[1];vis[u]=1;ans+=dist[u];for(int i=head[u];i;i=edge[i].next) {int v=edge[i].to,w=edge[i].val;if((!vis[v]) && dist[v]>w) {dist[v]=w;change(v);}}dist[u]=0x7fffffff;change(u);}printf("%lld\n",ans);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
反正都是距离是负的,我们判断每个点都作为出发点,然后初始的dist是0
然后从每个点开始跑spfa_dfs,如果有负环就回溯
回溯的时候可能错过一些vis点的恢复,所以我们要初始化一遍vis
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 200005#define mod 1000000007//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}struct node {int to,next,val;}edge[MAXN*4];int head[MAXN],sumedge,dist[MAXN];int n,m,T;void add(int u,int v,int c) {edge[++sumedge].to=v;edge[sumedge].next=head[u];edge[sumedge].val=c;head[u]=sumedge;}void addtwo(int u,int v,int c) {add(u,v,c);add(v,u,c);}bool vis[MAXN];bool spfa(int u) {vis[u]=1;for(int i=head[u];i;i=edge[i].next) {int v=edge[i].to,w=edge[i].val;if(dist[v]>dist[u]+w) {dist[v]=dist[u]+w;if(vis[v]) return true;else {if(spfa(v)) return true;}}}vis[u]=0;return false;}void solve() {memset(head,0,sizeof(head));//memset(edge,0,sizeof(edge));sumedge=0;n=read(),m=read();int x,y,z;siji(i,1,m) {x=read(),y=read(),z=read();if(z>=0) {addtwo(x,y,z);}else {add(x,y,z);}}memset(dist,0,sizeof(dist));memset(vis,0,sizeof(vis));siji(i,1,n) {if(spfa(i)) {puts("YE5");return;}}puts("N0");}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifT=read();while(T--) {solve();}}
我发现我并不是很会我当年做的这道题了……
NOI的食物链
我们要把所有的对应关系都考虑上
对于每个点建两个虚拟节点
x y如果可以是同类
x的敌人是y的敌人
x的食物是y的食物
x如果可以吃y
x的食物是y
y的敌人是x
x的敌人是y的食物
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 100005//#define ivorysiusing namespace std;typedef long long ll;int fa[3*MAXN];//1-n similar//n+1-2n its prey//2n+1-3n its enemyint n,k;int ans;int getfa(int x) {return x==fa[x] ? x : fa[x]=getfa(fa[x]);}void solve() {scanf("%d%d",&n,&k);siji(i,1,3*n) {fa[i]=i;}int op,x,y;siji(i,1,k) {scanf("%d%d%d",&op,&x,&y);if(x>n || y>n) {++ans;continue;}if(op==1) {int p=getfa(x),q=getfa(y);if(p==getfa(y+n) || p==getfa(y+2*n)){++ans;}else {fa[q]=p;fa[getfa(x+n)]=getfa(y+n);fa[getfa(x+2*n)]=getfa(y+2*n);}}else {int p=getfa(x);if(p==getfa(y) || p==getfa(y+n)) {++ans;}else {fa[getfa(y+2*n)]=getfa(x);fa[getfa(x+n)]=getfa(y);fa[getfa(x+2*n)]=getfa(y+n);}}}printf("%d\n",ans);}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
至今我还是对打标记心怀畏惧……其实标记还可以打很多东西……
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 黄金 Gold
有n个数和5种操作
add a b c:把区间[a,b]内的所有数都增加c
set a b c:把区间[a,b]内的所有数都设为c
sum a b:查询区间[a,b]的区间和
max a b:查询区间[a,b]的最大值
min a b:查询区间[a,b]的最小值
第一行两个整数n,m,第二行n个整数表示这n个数的初始值
接下来m行操作,同题目描述
输出描述 Output Description
对于所有的sum、max、min询问,一行输出一个答案
10 6
3 9 2 8 1 7 5 0 4 6
add 4 9 4
set 2 6 2
add 3 8 2
sum 2 10
max 1 7
min 3 6
49
11
4
1 < n ,m<=100000
这道题教会我一种新的打标记的方式……
线段树是大家喜闻乐见的RMQ,但是这个东西多了一个整体修改
我们针对整体修改,如果一个区间被整体修改了,那么它的加和的lazy必然也没有用了,如果被整体修改之后再加上加和,我们还需要用到这个lazy,所以我们要设两个开关,一个是整体修改的标记,一个是区间加的标记,如果有整体修改的标记先下放它,然后再判断有区间加的标记再下放
注意不能直接把在有整体修改的时候把区间加直接放到修改上,因为两次的区间也不一定覆盖啊……
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 100005//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0;char c=getchar();while(c<'0' || c>'9') c=getchar();while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res;}struct node {int l,r;ll minq,maxq,lazy,sum,setq;bool iscover,isadd;}tr[MAXN<<2];ll a[MAXN];int n,m;void build(int u,int l,int r) {tr[u].l=l;tr[u].r=r;if(l==r) {tr[u].sum=a[l];tr[u].maxq=a[l];tr[u].minq=a[l];return;}int m=(l+r)>>1;build(u<<1,l,m);build(u<<1|1,m+1,r);tr[u].minq=min(tr[u<<1].minq,tr[u<<1|1].minq);tr[u].maxq=max(tr[u<<1].maxq,tr[u<<1|1].maxq);tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;}void pushnode(int u) {if(tr[u].iscover) {if(tr[u<<1].l!=tr[u<<1].r) {tr[u<<1].lazy=0;tr[u<<1].isadd=0;tr[u<<1].iscover=1;}tr[u<<1].setq=tr[u].setq;tr[u<<1].minq=tr[u<<1].maxq=tr[u].setq;tr[u<<1].sum=(tr[u<<1].r-tr[u<<1].l+1)*tr[u].setq;if(tr[u<<1|1].l!=tr[u<<1|1].r) {tr[u<<1|1].lazy=0;tr[u<<1|1].isadd=0;tr[u<<1|1].iscover=1;}tr[u<<1|1].setq=tr[u].setq;tr[u<<1|1].minq=tr[u<<1|1].maxq=tr[u].setq;tr[u<<1|1].sum=(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].setq;tr[u].iscover=0;tr[u].setq=0;}if(tr[u].isadd){if(tr[u<<1].l!=tr[u<<1].r) {tr[u<<1].isadd=1;tr[u<<1].lazy+=tr[u].lazy;}tr[u<<1].minq+=tr[u].lazy;tr[u<<1].maxq+=tr[u].lazy;tr[u<<1].sum+=(tr[u<<1].r-tr[u<<1].l+1)*tr[u].lazy;if(tr[u<<1|1].l!=tr[u<<1|1].r) {tr[u<<1|1].isadd=1;tr[u<<1|1].lazy+=tr[u].lazy;}tr[u<<1|1].minq+=tr[u].lazy;tr[u<<1|1].maxq+=tr[u].lazy;tr[u<<1|1].sum+=(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].lazy;tr[u].lazy=0;tr[u].isadd=0;}}void update(int u) {tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;tr[u].minq=min(tr[u<<1].minq,tr[u<<1|1].minq);tr[u].maxq=max(tr[u<<1].maxq,tr[u<<1|1].maxq);}void add(int u,int l,int r,ll x) {if(tr[u].l==l && tr[u].r==r) {tr[u].isadd=1;tr[u].lazy+=x;tr[u].minq+=x;tr[u].maxq+=x;tr[u].sum+=(tr[u].r-tr[u].l+1)*x;return;}pushnode(u);int m=(tr[u].l+tr[u].r)>>1;if(r<=m) {add(u<<1,l,r,x);}else if(l>m) {add(u<<1|1,l,r,x);}else {add(u<<1,l,m,x);add(u<<1|1,m+1,r,x);}update(u);}void change(int u,int l,int r,ll c) {if(tr[u].l==l && tr[u].r==r) {tr[u].lazy=0;tr[u].isadd=0;tr[u].iscover=1;tr[u].setq=c;tr[u].minq=tr[u].maxq=c;tr[u].sum=(tr[u].r-tr[u].l+1)*c;return;}pushnode(u);int m=(tr[u].l+tr[u].r)>>1;if(r<=m) {change(u<<1,l,r,c);}else if(l>m) {change(u<<1|1,l,r,c);}else {change(u<<1,l,m,c);change(u<<1|1,m+1,r,c);}update(u);}ll qmax(int u,int l,int r) {if(tr[u].l==l && tr[u].r==r) {return tr[u].maxq;}int m=(tr[u].l+tr[u].r)>>1;pushnode(u);if(r<=m) {return qmax(u<<1,l,r);}else if(l>m) {return qmax(u<<1|1,l,r);}else {return max(qmax(u<<1,l,m),qmax(u<<1|1,m+1,r));}update(u);}ll qmin(int u,int l,int r) {if(tr[u].l==l && tr[u].r==r) {return tr[u].minq;}int m=(tr[u].l+tr[u].r)>>1;pushnode(u);if(r<=m) {return qmin(u<<1,l,r);}else if(l>m) {return qmin(u<<1|1,l,r);}else {return min(qmin(u<<1,l,m),qmin(u<<1|1,m+1,r));}update(u);}ll qsum(int u,int l,int r) {if(tr[u].l==l && tr[u].r==r) {return tr[u].sum;}int m=(tr[u].l+tr[u].r)>>1;pushnode(u);if(r<=m) {return qsum(u<<1,l,r);}else if(l>m) {return qsum(u<<1|1,l,r);}else {return qsum(u<<1,l,m)+qsum(u<<1|1,m+1,r);}update(u);}char c[15];void solve() {n=read();m=read();siji(i,1,n) {a[i]=read();}build(1,1,n);int a,b,x;siji(i,1,m) {scanf("%s",c+1);a=read();b=read();if(c[1]=='a') {x=read();add(1,a,b,x);}else if(c[1]=='s' && c[2]=='e') {x=read();change(1,a,b,x);}else if(c[1]=='s' && c[2]=='u') {printf("%lld\n",qsum(1,a,b));}else if(c[1]=='m' && c[2]=='i') {printf("%lld\n",qmin(1,a,b));}else {printf("%lld\n",qmax(1,a,b));}}}int main() {solve();}
区间修改,区间查询……不过这个题是单点,但是道理一样
我们考虑查分,每个查分的值都乘上整个序列,再删除掉重复的部分,两端分开维护
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 500005//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int n,m;ll a[MAXN],sum[MAXN];ll tr1[MAXN],tr2[MAXN];int lowbit(int x) {return x&(-x);}void change(ll *cur,int pos,ll k) {while(pos<=n) {cur[pos]+=k;pos+=lowbit(pos);}}ll _query(ll *cur,int pos) {ll res=0;while(pos>0) {res+=cur[pos];pos-=lowbit(pos);}return res;}ll query(int pos) {ll res=_query(tr1,pos)*pos+_query(tr2,pos)+sum[pos];return res;}void solve() {n=read();m=read();siji(i,1,n) {a[i]=read();sum[i]=sum[i-1]+a[i];}int op,x,y,k;while(m--) {op=read();if(op==1) {x=read();y=read();k=read();change(tr1,x,k);change(tr1,y+1,-k);change(tr2,x,((ll)x-1)*(-k));change(tr2,y+1,(ll)y*k);}else {x=read();ll ans=query(x)-query(x-1);printf("%lld\n",ans);}}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
简单易写的RMQ
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 1000005//define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int a[100006];int n,m;int st[100006][25];int log2[100006];int calc(int c) {int l=0;while(c) {l++;c>>=1;}return l-1;}void solve() {n=read();m=read();siji(i,1,n) {a[i]=read();st[i][0]=a[i];log2[i]=calc(i);}siji(j,1,20) {siji(i,1,n) {if((i+(1<<j)-1)>n) break;st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);}}int a,b;siji(i,1,m) {a=read();b=read();int len=log2[b-a+1];int ans=max(st[a][len],st[b-(1<<len)+1][len]);printf("%d\n",ans);}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.将某区间每一个数乘上x
3.求出某区间每一个数的和
第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k
操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k
操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果
输出包含若干行整数,即为所有操作3的结果。
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
17
2
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
我们要维护两个标记,一个是乘的标记mul,一个是加的标记add
更新乘法的时候需要用add×mul mul*mul
然后更新加法的时候add+add
pushnode的时候乘法标记直接相乘
加法标记乘上乘法标记再加上加法标记
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <vector>#include <stack>#define siji(i,x,y) for(int i=(x);i<=(y);++i)#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)#define MAXN 100005#define mod 1000000007//#define ivorysiusing namespace std;typedef long long ll;ll read() {ll res=0,neg=1;char c=getchar();while(c<'0' || c>'9') {if(c=='-') neg=-1;c=getchar();}while(c>='0' && c<='9') {res=res*10+c-'0';c=getchar();}return res*neg;}int n;ll a[MAXN],m,P;struct node {ll add,mul,sum;int l,r;}tr[MAXN*8];void update(int u) {tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%P;}void build(int u,int l,int r) {tr[u].l=l;tr[u].r=r;tr[u].mul=1;tr[u].add=0;if(l==r) {tr[u].sum=a[l];return;}int mid=(l+r)>>1;build(u<<1,l,mid);build(u<<1|1,mid+1,r);update(u);}void push_down(int u) {int l=tr[u].l,r=tr[u].r;tr[u<<1].sum=tr[u<<1].sum*tr[u].mul%P;tr[u<<1|1].sum=tr[u<<1|1].sum*tr[u].mul%P;tr[u<<1].mul*=tr[u].mul;tr[u<<1].mul%=P;tr[u<<1|1].mul*=tr[u].mul;tr[u<<1|1].mul%=P;int mid=(tr[u].l+tr[u].r)>>1;tr[u<<1].sum=(tr[u<<1].sum+tr[u].add*(mid-l+1)%P)%P;tr[u<<1|1].sum=(tr[u<<1|1].sum+tr[u].add*(r-mid)%P)%P;tr[u<<1].add=(tr[u<<1].add*tr[u].mul%P+tr[u].add)%P;tr[u<<1|1].add=(tr[u<<1|1].add*tr[u].mul%P+tr[u].add)%P;tr[u].mul=1;tr[u].add=0;}void change(int u,int ql,int qr,ll k,bool is_mul) {if(ql==tr[u].l && qr==tr[u].r) {if(is_mul) {tr[u].add=tr[u].add*k%P;tr[u].mul=tr[u].mul*k%P;tr[u].sum=tr[u].sum*k%P;}else {tr[u].add=(tr[u].add+k)%P;tr[u].sum=(tr[u].sum+(tr[u].r-tr[u].l+1)*k%P)%P;}return;}push_down(u);int mid=(tr[u].l+tr[u].r)>>1;if(qr<=mid) {change(u<<1,ql,qr,k,is_mul);}else if(ql>mid) {change(u<<1|1,ql,qr,k,is_mul);}else {change(u<<1,ql,mid,k,is_mul);change(u<<1|1,mid+1,qr,k,is_mul);}update(u);}ll query(int u,int ql,int qr) {if(tr[u].l==ql && tr[u].r==qr) {return tr[u].sum;}push_down(u);int mid=(tr[u].l+tr[u].r)>>1;if(qr<=mid) {return query(u<<1,ql,qr);}else if(ql>mid) {return query(u<<1|1,ql,qr);}else {return (query(u<<1,ql,mid)+query(u<<1|1,mid+1,qr))%P;}}void solve() {n=read();m=read();P=read();siji(i,1,n) a[i]=read();build(1,1,n);ll x,y,k,op;siji(i,1,m) {op=read();x=read();y=read();if(op==1) {k=read();change(1,x,y,k,1);}else if(op==2) {k=read();change(1,x,y,k,0);}else {ll res=query(1,x,y);printf("%lld\n",res);}}}int main() {#ifdef ivorysifreopen("f1.in","r",stdin);#endifsolve();}