1003
签到题,其实就是输出一个取模后的组合数,需要用到乘法逆元。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <string.h>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define ll long long
ll mod=1e9+7;
ll c[1010];
//扩展欧几里德
void ExEuclid(ll a,ll b,ll &x,ll &y,ll &q){
if(b==0){
x=1;y=0;q=a;
return;
}
ExEuclid(b,a%b,y,x,q);
y-=x*(a/b);
}
//乘法逆元
ll inv(ll num){
ll x,y,q;
ExEuclid(num,mod,x,y,q);
if(q==1)return (x+mod)%mod;
}
ll fab[1000010];
//组合数
ll C(ll n,ll k){
ll res=fab[n]*inv(fab[k]);
res%=mod;
res*=inv(fab[n-k]);
res%=mod;
return res;
}
int main(){
fab[0]=1;
for(int i=1;i<=1000000;i++){
fab[i]=fab[i-1]*i;
fab[i]%=mod;
}
int n,m;
while(cin>>n>>m){
int N=n+m-4;
int K=min(n,m)-2;
cout<<C(N,K)<<endl;
}
return 0;
}
1006
由于每个数均不相等,枚举
ai
,统计它作为中位数有多少种情况。方法是从下标
i
开始先往前扫一遍,得到每个前缀比
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <string.h>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define ll long long
int a[8010];
int ans[8010];
int tmp[16010];
int main(){
int n;
while(cin>>n){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++){
memset(tmp,0,sizeof(tmp));
int delta = 0;
for(int j=i;j>=1;j--){
if(a[j]>a[i]){
delta++;
}else if(a[j]<a[i]){
delta--;
}
tmp[8000+delta]++;
}
delta = 0;
for(int j=i;j<=n;j++){
if(a[j]>a[i]){
delta++;
}else if(a[j]<a[i]){
delta--;
}
ans[i] += tmp[8000-delta];
}
}
for(int i=1;i<=n;i++){
printf("%d",ans[i]);
if(i<n){
printf(" ");
}else{
printf("\n");
}
}
}
return 0;
}
1005
数据结构题。枚举每个
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <string.h>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define ll long long
int a[100010];
ll preSum[100010];
struct Seg{
int l,r;
bool operator<(const Seg &other)const{
return l<other.l;
}
}segs[100010];
int c[100010];
int lowbit(int x){
return x&(-x);
}
int n,k,m;
void update(int pos){
while(pos<=n){
c[pos]++;
pos+=lowbit(pos);
}
}
int query(int pos){
int res = 0;
while(pos){
res+=c[pos];
pos-=lowbit(pos);
}
return res;
}
void init(){
memset(c,0,sizeof(c));
}
int main(){
while(cin>>n>>k>>m){
init();
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
preSum[i] = preSum[i-1] + a[i];
}
for(int i=1;i<=m;i++){
scanf("%d%d",&segs[i].l,&segs[i].r);
}
sort(segs+1,segs+m+1);
//枚举
int K=1;
ll ans = 0;
for(int i=1;i<=n;i++){
while(K<=m && segs[K].l<=i){
update(segs[K].r);
K++;
}
int l = i;
int r = n;
int mid;
int res = -1;
while(l<=r){
mid = (l+r)>>1;
int cnt = query(n) - query(mid-1);
if(cnt>=k){
l=mid+1;
res = mid;
}else{
r=mid-1;
}
}
if(res!=-1){
ans = max(ans,preSum[res]-preSum[i-1]);
}
}
cout<<ans<<endl;
}
return 0;
}
1001
题目特意强调了数据随机(不然就做不了了)。。方法是枚举每个
ai
作为区间最大值,同时向左右拓展,直到左右都比
ai
大或者到达边界,更新每个长度的最大价值。此题解题依据为玄学(实际上复杂度一定不会超过
O(nlog(n))
)。
下面强行用数学解释一下玄学。先考虑最大的数,枚举到这个数时一定会拓展到左右边界才停止,也就是扩展
n
次。对于第二大的数,平均情形下,只会扩展
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <string.h>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define ll long long
ll a[100010];
ll ans[100010];
int main(){
int n;
while(cin>>n){
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++){
scanf("%I64d",&a[i]);
ans[1] = max(ans[1],a[i]*a[i]);
}
for(int i=1;i<=n;i++){
int l=i;
int r=i;
int len = 1;
int MIN = a[i];
while(l>1 || r<n){
if(a[l-1]>a[i] && a[r+1]>a[i]){
break;
}
len++;
if(a[l-1]>a[i] && r<n || (l==1 && a[r+1]<=a[i])){
r++;
if(a[r]<MIN){
MIN=a[r];
}
}else if(a[r+1]>a[i] && l>1 || (r==n && a[l-1]<=a[i])){
l--;
if(a[l]<MIN){
MIN=a[l];
}
}else if(l>1 && r<n && a[l-1]<=a[i] && a[r+1]<=a[i]){
if(a[l-1]>a[r+1]){
l--;
if(a[l]<MIN){
MIN=a[l];
}
}else{
r++;
if(a[r]<MIN){
MIN=a[r];
}
}
}else{
break;
}
ans[len] = max(ans[len],a[i]*MIN);
}
}
for(int i=1;i<=n;i++){
printf("%I64d\n",ans[i]);
}
}
return 0;
}