您的位置:首页 > 其它

2017-10-30离线赛总结

2017-10-30 19:53 204 查看
失分小结:

估分:150

实际分数:170

最后半个小时发现自己第一题敲错了,心态爆炸,拿暴力对拍,拍一组错一组

直到最后还没调出来,就只好把暴力丢上去,胡了50分

后面两题不敢想正解,就随便每题切了60分(后来发现机房的神犇门都想出了正解,泪奔)

两天一共375分 感觉两天都只敲了暴力 比省一线高了45分 如果是现场比赛估计也不会有这个分

收获:

对拍一定要是最暴力的!!!

题解:

第一题:

由除法的性质可知:由于组合数是可以递推的,只要在递推的过程中不断地取模,就能判断组合数是否能被k整除,且值不会超过int,然后就是前缀和维护,O(1)查询

#include<bits/stdc++.h>
using namespace std;
int ans[2005][2005];
int C[2005][2005];
int main(){
int T,k;
scanf("%d%d",&T,&k);
memset(C,-1,sizeof(C));
for(int i=1;i<=2000;i++){
C[i][i]=C[i][0]=1;
for(int j=1;j<i;j++){
C[i][j]=C[i-1][j-1]+C[i-1][j];
C[i][j]%=k;
}
}
for(int i=1;i<=2000;i++){
for(int j=1;j<=2000;j++){
ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];
if(!C[i][j])ans[i][j]++;
}
}
while(T--){
int n,m;
scanf("%d%d",&n,&m);
printf("%d\n",ans
[min(n,m)]);
}
return 0;
}


第二题

类似于曾经的一道瑞士轮,在本无序的序列中快速找到最大值

这里利用原序列,拆开后的大小序列组成的三个序列构成三个递减序列

然后用队列维护就好了 切分乱我心智

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,Q,u,v,t;
int A[100005];
long long ans[7000005];
template<class T>
struct Queue{
T a[10000000];
int l=1,r=0;
bool empty(){return l>r;}
void push(T x){a[++r]=x;}
T front(){return a[l];}
void pop(){l++;}
};
Queue<long long>q[3];
long long a[3];
int main(){
scanf("%d%d%d%d%d%d",&n,&m,&Q,&u,&v,&t);
for(int i=1;i<=n;i++)
scanf("%d",&A[i]);
sort(A+1,A+n+1);
for(int i=n;i>=1;i--)
q[0].push(A[i]);
for(int k=1;k<=m;k++){
ans[k]=-1e9;
for(int i=0;i<=2;i++){
a[i]=-1e9;
if(!q[i].empty())a[i]=q[i].front();
if(ans[k]<a[i])ans[k]=a[i];
}
for(int i=0;i<=2;i++){
if(a[i]==ans[k]){
q[i].pop();
b36c

a[i]+=Q*(k-1);
long long l1=1ll*a[i]*u/v;
long long l2=a[i]-l1;
if(l1>l2)swap(l1,l2);
q[1].push(l1-Q*k),q[2].push(l2-Q*k);
break;
}
}
ans[k]+=Q*(k-1);
}
for(int i=1;i<=m;i++)
if(i%t==0)printf("%lld ",ans[i]);
puts("");
for(int i=1;i<=n+m;i++){
int mx=-1e9,id=-1;
for(int k=0;k<=2;k++){
if(q[k].empty())continue;
if(q[k].front()>mx){
mx=q[k].front();
id=k;
}
}
q[id].pop();
if(i%t==0)printf("%d ",mx+m*Q);
}
puts("");
return 0;
}


第三题:

看到n=20内心毫无波澜又可以爆搜多水一些分了

裸裸的状压啊!!!

预处理:

任取两点作为函数的两点确定a,b

然后看这个函数能穿过多少个点,

主函数就是单纯的状压:

#include<bits/stdc++.h>
using namespace std;
const int M=21;
#define du double
#define EPS 1e-6

struct node{du x,y;}A[M];
int Sum[M*M],dp[1<<M],n,m,cnt,T;
template <class _> _ Abs(_ x){return x>=0?x:-x;}
template <class _> void chk_mi(_ &x,_ y){if(x==-1||x>y)x=y;}

bool check(node a,node b,du &fi,du &se){
du k1=a.x*a.x,k2=a.x,k3=a.y;
du k4=b.x*b.x,k5=b.x,k6=b.y;
du x=(k3*k5-k2*k6);
du y=(k5*k1-k2*k4);
if(y==0)return 0;
fi=x/y;
if(fi>=0)return 0;
se=(k3-k1*fi)/k2;
return 1;
}
bool True(node T,du a,du b){
du d=Abs(T.x*T.x*a+T.x*b-T.y);
return d<=EPS;
}
void init(){
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
du a,b;
if(!check(A[i],A[j],a,b))continue;
Sum[++cnt]|=1<<(i-1);
Sum[cnt]|=1<<(j-1);
for(int k=j+1;k<=n;k++){
if(k==i||k==j)continue;
if(!True(A[k],a,b))continue;
Sum[cnt]|=1<<(k-1);
}
}
}
}
int main(){
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
memset(dp,-1,sizeof(dp));
memset(Sum,0,sizeof(Sum));
cnt=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lf%lf",&A[i].x,&A[i].y);
init();
int tta=(1<<n)-1;
dp[0]=0;
for(int i=0;i<=tta;i++){
if(dp[i]==-1)continue;
for(int k=1;k<=cnt;k++)
chk_mi(dp[i|Sum[k]],dp[i]+1);
for(int k=0;k<n;k++)
if((i&(1<<k))==0)
chk_mi(dp[i|(1<<k)],dp[i]+1);
}
printf("%d\n",dp[tta]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: