有一我的有\(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); } }