总结:开始理解错了题目的意思,所以花了时间却没有打出来,先做了C;
然后B题有思路,打完之后没有调出来,就换回A题,做出来了以后,再做B题主要还是pow的问题,后来再主攻D;D的想法很多,开始想了单调队列,不过打不出来;后来分治就通了。主要还是要注意时间的调配,分散精力的优点是可以顾全大局,但是对于题目思考的深度肯定是差了一点
P1611 A 中位数计数
简析:效率O(n^2),显然满足条件的区间必是含奇数个数的区间,对于每个数,先往右扫一遍,求得其右边比其大的和比其小的数的个数的差x,然后再往左扫一遍,求其左边比起小的数和比起大的数的差,若一个数在这个区间为中位数,则若其右边比它大的比比它小的多x(有点绕),则其左边相反小的要比大的多x,,说白了就是delta(x)l=delta(x)r
这样x才能正好在中间位置,用一个数组记录一下差值为某个数的个数即可,注意要算上这个数自己。
#include<bits/stdc++.h>
#define N 8005
using namespace std;
int n,a[N],has[N<<1];
int main(){
while(~scanf("%d", &n)){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
int cnt=0,ans=0;
memset(has,0,sizeof(has));
has[8000]++;
for(int j=i+1;j<=n;j++){
cnt+=a[j]>a[i]?1:-1;
has[8000+cnt]++;
}
cnt=0;
ans+=has[8000];
for(int j=i-1;j>=1;j--){
cnt+=a[j]<a[i]?1:-1;
ans+=has[8000+cnt];
}
printf("%d%c",ans,i==n?'\n':' ');
}
}
}
P1606 B 全X数字
简析:一道简单的裸题,就是快速幂求和,花了时间主要还是因为模板不熟练。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int cas;
ll x,m,mod,c,ans;
ll p[105],sum[105];
ll pow(ll k,int d) {
if(k==1) return 10;
if(p[d]!=-1) return p[d];
ll s=(pow(k/2,d+1)*pow(k/2,d+1))%mod;
if(k%2==1) s=(s*10)%mod;
return p[d]=s;
}
ll getsum(ll k,int d) {
if(k==1) return 10;
if(sum[d]!=-1) return sum[d];
ll s=((getsum(k/2,d+1)*pow(k/2,d+1))%mod+getsum(k/2,d+1))%mod;
if(k%2==1) s=(s+pow(k,d))%mod;
return sum[d]=s;
}
int main(){
scanf("%d",&cas);
for(int i=1;i<=cas;i++) {
memset(sum,-1,sizeof(sum));
memset(p,-1,sizeof(p));
scanf("%lld%lld%lld%lld",&x,&m,&mod,&c);
m--;
ans=getsum(m,1)+1;
ans=(ans*x)%mod;
printf("Case #%d:\n",i);
if(ans%mod==c) printf("Yes\n");else printf("No\n");
}
return 0;
}
P1608 C 瞬间移动
简析:试着推一下会发现他是杨辉三角(话说之前考试考过)
这里只需要求C(m-2,n-2+m-2)即可。之后用逆元就完事。:
#include<bits/stdc++.h>
#define ll long long
#define N 1000005
#define mod 1000000007
using namespace std;
int n,m;ll c[N];
void gcd(int a,int b,ll &x,ll &y){
if (b==0){x=1;y=0;return;}
gcd(b,a%b,y,x);
y=y-(a/b)*x;
}
int main(){
while (~scanf("%d%d",&n,&m)){
c[0]=1;
for (int i=1;i<=n+m-4;i++){
ll x,y;gcd(i,mod,x,y);
ll tmp=(x+mod)%mod;
c[i]=(c[i-1]*(n+m-4-i+1))%mod;
c[i]=(c[i]*tmp%mod)%mod;
}
printf("%lld\n",c[m-2]);
}
}
P1607 D 区间的价值
简析:这道题用到了分治的思想(话说开始想过单调队列不过炸了)
首先,我们来定义solve(l,r)来求出区间[l,r]中各种区间长度的最大价值。
然后,我们找出[l,r]中的最小值。
固定了最小值以后,我们再去枚举最大值,算出各个价值。
我们能发现,随着区间变长,如果最小值是固定的,那么最大值只有可能越来越大,价值也会越来越大。
所以我们要把区间短的答案给区间长的更新。
如果最小值不是这一个呢?我们直接递归两边的就行了
我们再递归继续求solve(l,p-1)和solve(p+1,r),p是最小值的位置
由于数据是全随机的,所以不会退化到O(n^2)
#include<bits/stdc++.h>
#define ll long long
#define N 100005
using namespace std;
int n, a[N];
ll t[N], ans[N];
void solve(int l,int r) {
if(l>r) return;
int p=0;
for(int i=l;i<=r;i++)
if(!p||a[i]<a[p])p=i;
int w=r-l+1;
for(int i=1;i<=w;i++)t[i]=0;
for(int i=l;i<=p;i++)
t[p-i+1]=max(t[p-i+1],(ll)a[p]*a[i]);
for(int i=p;i<=r;i++)
t[i-p+1]=max(t[i-p+1],(ll)a[p]*a[i]);
ll pre=0;
for(int i=1;i<=w;i++) {
pre=max(pre,t[i]);
ans[i]=max(ans[i],pre);
}
solve(l,p-1);solve(p+1,r);
}
int main() {
while(~scanf("%d", &n)){
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
solve(1,n);
for(int i=1;i<=n;i++)
printf("%lld\n",ans[i]);
}
return 0;
}