今天山大附中的同学们跟我们一起来考试,他们好强啊,再次认识到了自己与其他人的差距;
本来可以和土哥一样是rk3的,不过不知道什么的原因,我的t2代码交c++就是50,交c++(NOI)就是100,直接rk3掉rk5了
T1简单的区间
这个题我第一眼看有点像之前写过的一道叫入镇曲的题目,也像noip模拟11的t3,都是维护一个区间的最值,
于是我写了个单调栈维护了一下区间的左端点和右端点,然后写了一个类似于入镇曲的O(n^n)的做法,拿了个50分;
其实这道题正解是写一颗主席树,然后可以O(nlog(n))写过,思路就和noip模拟11的t3一样,不过,我不会写主席树,还没学;
从fengwu那位STL之神那里学来了一手vector做法
其实思路大体没有啥变化,我们利用二分查找可以查出一个区间合法的个数,最后复杂度依然是Onlogn的,常数也比用主席树要小
1 #include<bits/stdc++.h> 2 #define int long long 3 #define lid id<<1 4 #define rid id<<1|1 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9') 11 { 12 if(ch=='-') f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9') 16 { 17 x=(x<<1)+(x<<3)+(ch^48); 18 ch=getchar(); 19 } 20 return x*f; 21 } 22 inline int max(int x,int y){if(x<y)return y;return x;} 23 inline int min(int x,int y){if(x<y)return x;return y;} 24 const int maxn=4e5+1; 25 int a[maxn],n,k; 26 int pre[maxn]; 27 int le[maxn],re[maxn]; 28 stack<int >s; 29 int mod[1000001]; 30 signed main() 31 { 32 n=read(),k=read(); 33 for(int i=1;i<=n;i++) 34 { 35 a[i]=read(); 36 pre[i]=(a[i]+pre[i-1])%k; 37 } 38 for(int i=1;i<=n;i++) 39 { 40 while(!s.empty()&&a[i]>a[s.top()]) 41 s.pop(); 42 le[i]=s.empty()?1:s.top()+1; 43 s.push(i); 44 } 45 while(!s.empty()) 46 s.pop(); 47 for(int i=n;i;i--) 48 { 49 while(!s.empty()&&a[i]>=a[s.top()]) 50 s.pop(); 51 re[i]=s.empty()?n:s.top()-1; 52 s.push(i); 53 } 54 int ans=0,jb=0; 55 for(int i=1;i<=n;i++) 56 { 57 int l=le[i],r=re[i]; 58 int maxx=a[i]%k; 59 for(int j=l;j<i;j++) 60 mod[pre[j-1]]++; 61 ans+=mod[(pre[i]-maxx+k)%k]; 62 mod[pre[i-1]]++; 63 for(int j=i+1;j<=r;j++) 64 ans+=mod[(pre[j]-maxx+k)%k]; 65 for(int j=l;j<=i;j++) 66 mod[pre[j-1]]=0; 67 } 68 cout<<ans; 69 }
1 #include<bits/stdc++.h> 2 #define int long long 3 #define lid id<<1 4 #define rid id<<1|1 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9') 11 { 12 if(ch=='-') f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9') 16 { 17 x=(x<<1)+(x<<3)+(ch^48); 18 ch=getchar(); 19 } 20 return x*f; 21 } 22 inline int max(int x,int y){if(x<y)return y;return x;} 23 inline int min(int x,int y){if(x<y)return x;return y;} 24 const int maxn=1e6+1; 25 int a[maxn],n,k; 26 int pre[maxn],ans=0; 27 int le[maxn],re[maxn]; 28 stack<int >s; 29 int mod[1000001]; 30 vector<int > q[1000001]; 31 void cz(int i,int l,int r) 32 { 33 if(i-l<r-i) 34 { 35 for(int j=l;j<=i;j++) 36 { 37 int tmp=(pre[j-1]+a[i])%k; 38 int ans1=lower_bound(q[tmp].begin(),q[tmp].end(),i)-q[tmp].begin(); 39 int ans2=upper_bound(q[tmp].begin(),q[tmp].end(),r)-q[tmp].begin(); 40 ans+=ans2-ans1; 41 } 42 } 43 else 44 { 45 for(int j=i;j<=r;j++) 46 { 47 int tmp=(pre[j]-(a[i]%k)+k)%k; 48 int ans1=lower_bound(q[tmp].begin(),q[tmp].end(),l-1)-q[tmp].begin(); 49 int ans2=upper_bound(q[tmp].begin(),q[tmp].end(),i-1)-q[tmp].begin(); 50 ans+=ans2-ans1; 51 } 52 } 53 } 54 signed main() 55 { 56 n=read(),k=read(); 57 q[0].push_back(0); 58 for(int i=1;i<=n;i++) 59 { 60 a[i]=read(); 61 pre[i]=(a[i]+pre[i-1])%k; 62 q[pre[i]].push_back(i); 63 } 64 for(int i=1;i<=n;i++) 65 { 66 while(!s.empty()&&a[i]>a[s.top()]) 67 s.pop(); 68 le[i]=s.empty()?1:s.top()+1; 69 s.push(i); 70 } 71 while(!s.empty()) s.pop(); 72 for(int i=n;i>=1;i--) 73 { 74 while(!s.empty()&&a[i]>=a[s.top()]) 75 s.pop(); 76 re[i]=s.empty()?n:s.top()-1; 77 s.push(i); 78 } 79 for(int i=1;i<=n;i++) 80 cz(i,le[i],re[i]); 81 cout<<ans-n; 82 }
T2简单的玄学
看题目,怎么办,好象是概率题,再仔细一点,原来就是个数学题,推了大概半个小时,直接就推出来了,其实只要掌握好了数论,
这种题目确实不是很难(只不过让评测机吃掉了50分);
下面直接说一下正解,题目上说让我们求出至少有两个数是相等的概率,那我们可以求出1减去一个都不相等的概率,得出的结果肯定是一样的
首先,全部的情况肯定是2^nm,那么分母就定了,完全不相等的情况就是从(2^n)连乘到(( 2^n )-m+1),题目中告诉我们说
分子和分母都要化成最简的,那么我们要约分啊
由于分母是2的次幂,所以它的质因子只有2,那我们就要找上面那个数字中2的个数,那么我们应该怎么来找呢??
首先我们应该清楚一条性质2^k-x里2的因子数=x里面2的因子数。证明:设x=x/(2^y)*(2^y),2^k=(2^(k-y)*2^y),那么很显然2^(k-y)-x不是偶数
那么剩下就没啥了,挺基础的一些操作
#include<bits/stdc++.h> #define ll long long #define int long long using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int mod=1e6+3; const int phi=1e6+2; inline int ksm(int j,int k,int l) { int f=1; j=j%l; while(k>0) { if(k%2==1) { f=(f*j)%l; } k*=0.5; j=(j*j)%l; } return f; } inline int gcd(int a,int b) { if(!b) return a; return gcd(b,a%b); } int n,m; signed main() { n=read(),m=read(); if(n==1) { cout<<1<<" "<<1; return 0; } int maxx=ksm(2,n%phi,mod); int y=ksm(maxx,m%phi,mod); int x=1; int sum=n; for(int i=0;i<=m-1;i++) { x=(x*(maxx-i))%mod; if(!x) break; }//2×500002%mod=1 所以2的逆元就是500002 for(int i=1;((ll)1<<i)<=m-1;i++) { sum+=(m-1)/((ll)1<<i); } y=(y*ksm(500002,sum,mod))%mod; x=(x*ksm(500002,sum,mod))%mod; cout<<(y-x+mod)%mod<<" "<<y; }
T3简单的填数
其实挺难的,不,是真的十分难,唉,果然还是我太弱了
题解简直不说人话,就是模拟,然后分情况讨论
up代表上界,down代表下界;
先不要考虑已经填了的,up2位一进,down5位一进
然后再考录已经填了的,a[ i ]>上界就是不合法状态
如果a[ i ]==up,那么取min(2,up);
否则让up=a[ i ],次数变成2;
下界类似,就不再写了
#include<bits/stdc++.h> using namespace std; const int maxn=1010101; struct node { int cnt,x; }up[maxn],down[maxn]; int a[maxn],vis[maxn],n; inline int min(int x,int y){return x<y?x:y;} inline int max(int x,int y){return x>y?x:y;} inline void swap(int &x,int &y){x^=y^=x^=y;} inline int abs(int x){return x<0?-x:x;} inline int gcd(int x,int y){return y?x:gcd(y,x%y);} inline int lcm(int x,int y){return x/gcd(x,y)*y;} inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int main() { n=read(); for(int i=1;i<=n;i++) a[i]=read(); if(a[1]!=1&&a[1]!=0) { puts("-1"); return 0; } up[1].cnt=1,up[1].x=1; down[1].cnt=1,down[1].x=1; for(int i=2;i<=n;i++) { up[i]=up[i-1]; down[i]=down[i-1]; if(++up[i].cnt>2) up[i].cnt=1,up[i].x++; if(++down[i].cnt>5) down[i].cnt=1,down[i].x++; if(a[i]) { if(up[i].x>a[i]) up[i].x=a[i],up[i].cnt=2; if(down[i].x<a[i]) down[i].x=a[i],down[i].cnt=1; if(up[i].x<a[i]||down[i].x>a[i]) { cout<<-1; return 0; } } } if(up[n].cnt==1) up[n].x=up[n-1].x; if(up[n].x<down[n].x) { puts("-1"); return 0; } printf("%d\n",up[n].x); vis[up[n].x]=1; a[n]=up[n].x; for(int i=n-1;i>=1;i--) { if(!a[i]) { int t=min(a[i+1],up[i].x); if(vis[t]==5) --t; a[i]=t; } vis[a[i]]++; } for(int i=1;i<=n;i++) printf("%d ",a[i]); }