今天做的是11年day2的题(不愧是day2,做得完全没有思路,首测只有一百分。
第一题——计算系数(factor)
- 其实这一道题就是数学的多项式定理,展开一下就知道了规律,然后该递推递推,该快速幂就快速幂简单ac
- 好吧我还是细讲一下。给定的是 (ax+by)k ( a x + b y ) k 的公式,而展开之后就是 akxk+s2ak−1xk−1by+... a k x k + s 2 a k − 1 x k − 1 b y + . . . (这里的s是前置系数)。手打几个k就可以发现s系数是杨辉三角的原理,那么就可以用递推求得 s[k][m+1] s [ k ] [ m + 1 ] 而后面的a和b就通过快速幂来求。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
void fff(){
freopen("factor.in","r",stdin);
freopen("factor.out","w",stdout);
}
const int MAXN=100020;
const int LIMIT=10007;
int n,m,k,a,b;
int s[1010][1010];
int ans;//mod LIMIT
void init(){
memset(s,0,sizeof(s));
s[1][1]=1;
s[1][2]=1;
for (int i=2;i<=k;i++){
for (int j=1;j<=i+1;j++)
s[i][j]=(s[i-1][j]+s[i-1][j-1])%LIMIT;
}
}
int p(int t,int step){
if(step==1){
return t%LIMIT;
}
int temp=p(t,step/2)%LIMIT;
int ss=temp*temp%LIMIT;
if(step%2==1){
return ss*(t%LIMIT)%LIMIT;
}
return ss;
}
int main(){
fff();
scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);
init();
ans=1;
ans=(p(a,n)%LIMIT)*(p(b,m)%LIMIT)%LIMIT;
ans*=s[k][m+1]%LIMIT;
ans=ans%LIMIT;
cout<<ans;
return 0;
}
第二题——聪明的质监员(qc)
- 这道题其实本质上比我想的要简单…是我想得太多缩手缩脚的不敢下手。
- 简述下题意,让你枚举w使得给定的m段区间里符合 Yi=∑j1∗∑jv[j](j∈[Li,Ri]且wj>W) Y i = ∑ j 1 ∗ ∑ j v [ j ] ( j ∈ [ L i , R i ] 且 w j > W )
而最终所得的 Y=∑mi=1Yi Y = ∑ i = 1 m Y i 与给定的S相差最小
这第一眼就知道是二分题,但是这个数据有点大我有点怕…最终打了再求单个w对应的Y用了 n2 n 2 的算法十分愚蠢。看了标程才知道这道题用前缀和来优化。
- 先讲二分,可以知道w越大Y就越小,那么就只需要找到离S最近的Y(w)>S就可以了,然后再来看Y(w+1)和他谁近就好了。
- 讲下前缀和:枚举1到 i i ,设cnt是合法个数,sum是合法总和。查询的时候减下就行了。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
void fff(){
freopen("qc.in","r",stdin);
freopen("qc.out","w",stdout);
}
const int MAXN=200010;
struct num{
long long w,v;
}a[MAXN];
struct siz{
int L,R;
bool operator < (const siz x) const {
if(L==x.L) return R<x.R;
return L<x.L;
}
}b[MAXN];
int n,m;
const long long MAX_S = 1e13;
long long s,minn,maxx,ans;
long long sum[MAXN];
long long cnt[MAXN];
long long get_y(long long w){
long long Y=0;
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++){
sum[i]=sum[i-1];
cnt[i]=cnt[i-1];
if(a[i].w>=w){
sum[i]+=a[i].v;
cnt[i]=cnt[i-1]+1;
}
}
for (int i=1;i<=m;i++){
long long s=sum[b[i].R+1]-sum[b[i].L],c=cnt[b[i].R+1]-cnt[b[i].L];
Y+=s*c;
}
return Y;
}
long long Abs(long long x){
if(x<0) x=-x;
return x;
}
void solve(long long l,long long r){
while (l<r-1){
long long mid=(l+r)>>1;
long long temp1=get_y(mid);
if(temp1<=s){
r=mid;
}else{
l=mid;
}
}
ans=min(Abs(s-get_y(r)),Abs(get_y(r-1)-s));
}
int main(){
// fff();
scanf("%d%d",&n,&m);
cin>>s;
minn=MAXN*10;
maxx=0;
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++){
scanf("%ld%ld",&a[i].w,&a[i].v);
minn=min(minn,a[i].w);
maxx=max(maxx,a[i].w);
}
for (int i=1;i<=m;i++){
scanf("%d%d",&b[i].L,&b[i].R);
b[i].L--;
b[i].R--;
}
solve(minn,maxx);
cout<<ans;
return 0;
}
第三题——观光公交(bus)
- 这道题真的是很玄学啊。本来以为要用动规的,但我同学暴力模拟维护就解决了….大概是数据水吧…
- 先说题意吧。有n个站点n-1条路。每个站点有乘客上车有乘客下车。车子有k个氮气瓶用来加速,每瓶使路上花的时间减1。而每个乘客的出发时间在车子到之后,那么车上的每个人都要等。求总共花的时间的最小值。
- 讲下算法。
- 首先可以知道一点,设是在第i个点最早到达时间,
tLIMIT[i]
t
L
I
M
I
T
[
i
]
是第i个点上人出发时间
Ti
T
i
的最大值。那么这个出发的时间可以确定为一个公式:
- ti=max(ti−1,tLIMITi−1)+Di−1 t i = m a x ( t i − 1 , t L I M I T i − 1 ) + D i − 1
- 那么则可以得知从 Ai A i 到 Bi B i 的旅客的旅游时间就是 tBi−Ti t B i − T i
- 然后就是简单的暴力贪心模拟枚举操作了
- 贪心的想法就是在人密度最多的路上使用,但由于使用后会影响 ti t i 的值,所以只好一瓶一瓶用。最后全部都用光了我就可以像没有氮气一样来模拟计算了。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
void fff(){
freopen("bus.in","r",stdin);
freopen("bus.out","w",stdout);
}
const int MAXM=10010;
const int MAXN=1010;
struct guest{
int T,A,B;
}a[MAXM];
int n,m,k,all;
int D[MAXN];
int tLIMIT[MAXN],out_num[MAXN];
int t[MAXN];
int main(){
// fff();
scanf("%d%d%d",&n,&m,&k);
all=0;
for (int i=1;i<n;i++) scanf("%d",&D[i]);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&a[i].T,&a[i].A,&a[i].B);
tLIMIT[a[i].A]=max(tLIMIT[a[i].A],a[i].T);
out_num[a[i].B]++;
all-=a[i].T;
}
t[1]=out_num[1];
for (int o=1;o<=k;o++){
for (int i=2;i<=n;i++){
t[i]=max(t[i-1],tLIMIT[i-1])+D[i-1];//重新更新t[i]
}
int pos=0,maxx=0;
for (int i=1;i<n;i++){
if(!D[i]) continue;
int tt=0;
for (int j=i+1;j<=n;j++){
tt+=out_num[j];
if(t[j]<=tLIMIT[j]) break;
}
if(tt>maxx) {//找到密度最大
maxx=tt;
pos=i;
}
}
if(!pos) break;
D[pos]--;//使用
}
for (int i=2;i<=n;i++){
t[i]=max(t[i-1],tLIMIT[i-1])+D[i-1];
}
for (int i=1;i<=n;i++){
all+=t[i]*out_num[i];
}
cout<<all;
return 0;
}