有一我的有\(n\)个数,最小的是\(A\),最大的是\(B\),其余数位置,问一共有多少种和的可能状况。html
显然可以取到的是一段连续值,那么求出最小值和最大值就好了。ios
#include<iostream> using namespace std; long long n,a,b,l,r; int main() { cin>>n>>a>>b; if(a>b){puts("0");return 0;} l=b+(n-1)*a,r=a+(n-1)*b; cout<<max(0ll,r-l+1)<<endl; return 0; }
有一个电梯,有\(n\)层楼,给定了一个字符串\(S\),\(S_i\)告诉你了这个电梯在这一层只能向上走或者是向下走。spa
如今问你任意两层之间须要坐几回电梯,求出全部状况的和。code
显然答案不是\(1\)就是\(2\),那么对于每一个位置判断一下有多少个是\(1\)有多少个是\(2\)就好了。htm
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n;long long ans; char S[100010]; int main() { scanf("%s",S+1);n=strlen(S+1); for(int i=1;i<=n;++i) if(S[i]=='U')ans+=(n-i)+2*(i-1); else ans+=2*(n-i)+(i-1); printf("%lld\n",ans); return 0; }
有一个网格图,一些格子被涂蓝了,保证蓝色的格子构成了一棵树。blog
每次询问问你一个子矩形内蓝色格子构成的联通块数量。排序
既然是一棵树,那么联通块个数等于点数减去边数,而后就很好作了。递归
#include<iostream> #include<cstdio> using namespace std; #define MAX 2010 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int n,m,Q; char g[MAX][MAX]; int s[MAX][MAX],sl[MAX][MAX],su[MAX][MAX]; int Calc(int s[][MAX],int x1,int y1,int x2,int y2) { if(x1>x2||y1>y2)return 0; return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]; } int main() { n=read();m=read();Q=read(); for(int i=1;i<=n;++i)scanf("%s",g[i]+1); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { s[i][j]=(g[i][j]=='1'); sl[i][j]=(g[i][j]=='1'&&g[i][j-1]=='1'); su[i][j]=(g[i][j]=='1'&&g[i-1][j]=='1'); } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1]; sl[i][j]+=sl[i-1][j]+sl[i][j-1]-sl[i-1][j-1]; su[i][j]+=su[i-1][j]+su[i][j-1]-su[i-1][j-1]; } while(Q--) { int x1=read(),y1=read(),x2=read(),y2=read(); printf("%d\n",Calc(s,x1,y1,x2,y2)-Calc(sl,x1,y1+1,x2,y2)-Calc(su,x1+1,y1,x2,y2)); } return 0; }
由\([A,B]\)之间的数构成的非空集合的\(or\)值有多少种。ci
感受颇有想法,然而就是不会作,。。。字符串
首先\(A=B\)不用管了,只考虑\(A=B\) 的状况,那么先找到二进制位下\(A,B\)不一样的第一位,前面的部分能够直接丢掉,由于对于答案不产生影响。
假设最高位是\(k\),那么咱们把集合分红两个部分,一半是\([A,2^k)\),另外一半是\([2^k,B]\),在第一部分里面任意选数只能选出\([A,2^k)\)的值,在第二部分中选数,考虑\(B\)的次大二进制为\(l\),那么能够选的范围在\([2^k,2^k+2^l)\)之间,若是两个部分同时选的话,那么能够获得的范围是\([2^k+A,2^{k+1})\)。
这三个部分取并就是答案了。
#include<iostream> #include<cstdio> using namespace std; #define ll long long ll A,B,ans; int main() { cin>>A>>B; if(A==B){puts("1");return 0;} int k=60; for(;~k;--k) { if((A>>k&1)^(B>>k&1))break; if(A>>k&1)A^=1ll<<k,B^=1ll<<k; } int l=k-1; while((~l)&&!(B&(1ll<<l)))--l; ll L=(!~l)?B:((1ll<<k)+(1ll<<(l+1))-1); ll R=(1ll<<k)+A; ans=(1ll<<(k+1))-A; if(L+1<R)ans-=R-L-1; printf("%lld\n",ans); return 0; }
数轴上有\(n\)我的,第\(i\)我的一开始在\(X_i\)位置,用\(v_i\)的初速度往正方向移动。一开始有若干我的被染色,被染色的人若是碰到了未被染色的人,就把会未被染色的人给染色。
问在全部的\(2^n\)种初始的染色方案中,有多少种染色方法在足够长的时间以后可以让全部人都被染色。
首先最终的序列必定是惟一的,即全部人都按照速度的顺序依次排开,而且全部人相遇的时间也是固定的,那么惟一须要考虑的就只有染色的状况。
考虑如今只有一个点被染色,考虑哪些点会被染色。显然是位置在它左侧其速度比它快的,以及位置在它右侧而且速度比它慢的点会被追上。
把全部点按照速度从大往小排序,那么,对于一个点,在速度比它大的点中找到最靠右的那个,记作\(L\)。在速度比它小的点中找到最靠左的那个,记作\(R\) 。那么\([L,R]\)都会被染色(看起来挺容易证实的)。
因而问题等价于有\(n\)个区间,选出若干个使得他们的并刚好是全集的方案数。
那么这个东西直接\(dp\)就好了。
把全部区间按照右端点排序,设\(f[i]\)表示考虑了前\(i\)个区间,且\([1,R_i]\)都已经被覆盖的方案数。
这个东西能够用前缀和很方便的进行转移。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #define MOD 1000000007 #define MAX 200200 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Node{int x,v;}p[MAX]; int S[MAX],top; bool operator<(Node a,Node b){return a.v<b.v;} struct Line{int l,r;}a[MAX]; bool operator<(Line a,Line b){if(a.r!=b.r)return a.r<b.r;return a.l<b.l;} int f[MAX],s[MAX],ans,n; int main() { n=read(); for(int i=1;i<=n;++i)p[i].x=read(),p[i].v=read(); sort(&p[1],&p[n+1]); for(int i=1;i<=n;++i) { if(!top||p[i].x>p[S[top]].x)S[++top]=i; int l=1,r=top,ret=i; while(l<=r) { int mid=(l+r)>>1; if(p[S[mid]].x>=p[i].x)r=mid-1,ret=mid; else l=mid+1; } a[i].l=S[ret]; } top=0; for(int i=n;i>=1;--i) { if(!top||p[i].x<p[S[top]].x)S[++top]=i; int l=1,r=top,ret=i; while(l<=r) { int mid=(l+r)>>1; if(p[S[mid]].x<=p[i].x)r=mid-1,ret=mid; else l=mid+1; } a[i].r=S[ret]; } sort(&a[1],&a[n+1]); for(int i=1,p=1;i<=n;++i) { while(a[p].r<a[i].l-1)++p; f[i]=(s[i-1]-s[p-1]+MOD)%MOD; if(a[i].l==1)f[i]=(f[i]+1)%MOD; if(a[i].r==n)ans=(ans+f[i])%MOD; s[i]=(s[i-1]+f[i])%MOD; } printf("%d\n",ans); return 0; }
给你\(n,m\),求\(x\in [1,n],y\in[1,m]\)中,让\(x,y\)作展转相除的最大递归次数是多少。
并求出可以取到最大值的\((x,y)\)的对数。
首先最大值很容易算,不难发现就是斐波那契数列最大的相邻的两项,知足都在范围内。
考虑怎么统计答案,咱们不妨令\(x\ge y\)。假设最大值是\(k\),递归次数是\(g(x,y)\),\(f_i\)为斐波那契数列第\(i\)项,且\(f_0=f_1=1\)。 那么\(g(x,y)\)的最大值为知足\(f_{k+1}\le x,f_{k}\le y\)的最大\(k\)。
剩下的部分戳这里吧
#include<iostream> #include<cstdio> #include<vector> using namespace std; #define ll long long #define MOD 1000000007 #define pi pair<ll,ll> #define mp make_pair inline ll read() { ll x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } ll f[110]; vector<pi> a[110]; int main() { int T=read(); f[0]=f[1]=1; for(int i=2;i<=100;++i)f[i]=f[i-1]+f[i-2]; a[1].push_back(mp(1,2));a[1].push_back(mp(1,3));a[1].push_back(mp(1,4)); for(int i=1;i<=100;++i) for(int j=0,l=a[i].size();j<l;++j) { ll x=a[i][j].second,y=a[i][j].first+x; while(y<=f[i+3]+f[i])a[i+1].push_back(mp(x,y)),y+=x; } while(T--) { ll n=read(),m=read();if(n>m)swap(n,m); if(n==1&&m==1){puts("1 1");continue;} int p,ans=0;for(int i=1;;++i)if(!(n>=f[i]&&m>=f[i+1])){p=i-1;break;} printf("%d ",p);if(p==1){printf("%lld\n",(n%MOD)*(m%MOD)%MOD);continue;} for(int j=0,l=a[p-1].size();j<l;++j) { ll x=a[p-1][j].first,y=a[p-1][j].second; if(y<=n)ans=(ans+(m-x)/y)%MOD; if(y<=m)ans=(ans+(n-x)/y)%MOD; } printf("%d\n",ans); } }