10.13 上午 考試
阿新 • • 發佈:2017-10-13
san 區間 mic 大於等於 mil ons spa ios 技術
T1
直接二分就好了
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <cstdlib> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; ll n; int a,b,d; ll check(ll x) { ll t1,t2; t1T1=(ll)(x-a-1)/d+1; if(x>b) t2=(ll)(x-b-1)/d+1; else t2=(ll)(b-x-1)/d+1; return t1+t2; } ll work1() { ll ans=max(a,b),l=max(a,b),r=((ll)1<<60),mid,temp; while(l<=r) { mid=(l+r)>>1; temp=check(mid); if(temp<=n&&ans<mid) ans=mid; if(l>=r) break; if(temp<=n) l=mid+1; else r=mid-1; } return ans; } int main(){ //freopen("T1.in","r",stdin); scanf("%lld%d%d%d",&n,&d,&a,&b); --n; cout<<work1(); }
T2
預處理出來每個點
$L_i$ i左邊第一個比它大的點的位置
$R_i$ i右邊第一個大於等於它的位置(這樣是為了統計的時候不重復)
那麽K==$a_i$的區間個數就是$$\sum_{a_i==K}(i-L_i)(R_i-i)$$
然後求一下前綴和和後綴和就行了
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <cstdlib> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; inline int read() { char q=getchar();int ans=0; while(q<‘0‘||q>‘9‘)q=getchar(); while(q>=‘0‘&&q<=‘9‘){ans=ans*10+q-‘0‘;q=getchar();} return ans; } inline char readchar() { char q=getchar(); while(q!=‘<‘&&q!=‘>‘&&q!=‘=‘)q=getchar(); return q; } const int N=100006; struct JI { int ff,pos,val; bool friend operator < (JI a,JI b) { return a.val<b.val; } }ji[N*3]; int ccc; int now; int n,Q; int a[N],K[N]; char op[N]; void lisan() { now=0; sort(ji+1,ji+1+ccc); for(int i=1;i<=ccc;++i) { if(ji[i].val!=ji[i-1].val) ++now; if(ji[i].ff==1) a[ji[i].pos]=now; else K[ji[i].pos]=now; } } int L[N],R[N]; ll num[N*3],presum[N*3],behsum[N*3]; int zhan[N*2],he; void work() { a[0]=a[n+1]=0x7fffffff; he=0;zhan[++he]=0; for(int i=1;i<=n;++i) { while(a[zhan[he]]<=a[i])--he; L[i]=zhan[he]; zhan[++he]=i; } he=0;zhan[++he]=n+1; for(int i=n;i>=1;--i) { while(a[zhan[he]]<a[i])--he; R[i]=zhan[he]; zhan[++he]=i; } for(int i=1;i<=n;++i) num[a[i]]+=(ll)(i-L[i])*(R[i]-i); for(int i=1;i<=now;++i) presum[i]=presum[i-1]+num[i]; for(int i=now;i>=1;--i) behsum[i]=behsum[i+1]+num[i]; for(int i=1;i<=Q;++i) { if(op[i]==‘=‘) printf("%lld\n",num[K[i]]); else if(op[i]==‘<‘) printf("%lld\n",presum[K[i]-1]); else printf("%lld\n",behsum[K[i]+1]); } } int main(){ freopen("T2.in","r",stdin); n=read();Q=read(); for(int i=1;i<=n;++i) { ++ccc; ji[ccc].val=read(); ji[ccc].ff=1; ji[ccc].pos=i; } for(int i=1;i<=Q;++i) { op[i]=readchar(); ++ccc; ji[ccc].ff=2; ji[ccc].val=read(); ji[ccc].pos=i; } lisan(); work(); }T2
T3
$f_i$ 所有排列長度為 i 排完序所需要的總步數
那麽 $$f_i=i*f_{i-1}+(2^{i-1}-1)*fac_{i-1}$$
我們考慮第 i 位都是誰
是i時,直接加上$f_{i-1}$
1時,加上$f_{i-1}+2^0*fac_{i-1}$
...
然後求和就可以 $O(n)$ 了
解釋一下轉移:
fac就是階乘,即長度為 i-1 的排列個數
每次在長度i-1的後面添加一個數x (當然,前i-1個數裏可能有i)
那把x扔到第x位需要$2^{x-1}$次(i需要0次)
證明:
比如 3 1 2 弄成 1 2 3 需要3次
4 1 2 3 弄成 1 2 4 3 也需要3次
因為 4可以看成3 再把 3扔到開頭到有序,又相當於重復了一遍3 1 2 到 1 2 3 的過程
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <cstdlib> #include <algorithm> #define ll long long #define dd double #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int N=100006; const int mod=1e9+7; ll qpow(ll a,int ci) { ll ans=1; while(ci) { if(ci&1) ans=ans*a%mod; a=a*a%mod; ci>>=1; } return ans; } ll jie[N],jieni[N]; void chu() { jie[0]=1; for(int i=1;i<N;++i) jie[i]=jie[i-1]*i%mod; jieni[N-1]=qpow(jie[N-1],mod-2); for(int i=N-2;i>=1;--i) jieni[i]=jieni[i+1]*(ll)(i+1)%mod; jieni[0]=1; } int n; ll f[N],mi[N]; int main(){ chu(); scanf("%d",&n); mi[0]=1; for(int i=1;i<=n;++i) { mi[i]=mi[i-1]*2%mod; f[i]=f[i-1]*i%mod+(mi[i-1]-1+mod)%mod*jie[i-1]%mod; } printf("%lld", f[n]%mod*jieni[n]%mod ); }T3
想不出來也是一種無奈...
10.13 上午 考試