T1:组合数问题
考察知识:数学,记忆化
算法难度:XX+ 实现难度:XX+
分析:
设 表示中 的数的个数
状态转移:,其中cnt表示
预处理之后,对于每个输入我们直接输出答案即可
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[2018][2018],ans[2018][2018],n,m,k,t;
int main(){
scanf("%d%d",&t,&k);
ans[0][0]=0;
for(int i=0;i<=2000;i++) a[i][i]=a[i][0]=1;
for(int i=1;i<=2000;i++){
int cnt=0;
for(int j=1;j<i;j++){
a[i][j]=a[i-1][j]+a[i-1][j-1];
a[i][j]%=k;
if(!a[i][j]) cnt++;
ans[i][j]=ans[i-1][j]+cnt;
}
ans[i][i]=ans[i-1][i-1]+cnt;
}
while(t--){
scanf("%d%d",&n,&m);
if(m>n) m=n;
printf("%d\n",ans[n][m]);
}
return 0;
}
T2:蚯蚓
考察知识:队列,模拟
算法难度:XXX+ 实现难度:XXX+
分析:
不想多说:
- 每次蚯蚓增长可以用一个变量表示,不必直接模拟
- 这道题可以用优先队列或二叉堆实现,代码简单,但是会超时
- 分析后发现其实队列本身具有单调性,我们分别维护3个保持单调性的队列即可
代码:
85代码:(二叉堆实现)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=15000000;
#define ui unsigned int
int n,m,q,u,v,t,k;
int heap[maxn],np;
void push(int k){
heap[++np]=k;
int x=np,y=np/2;
while(y>0){
if(heap[y]<heap[x]) swap(heap[x],heap[y]),x=y,y/=2;
else break;
}
}
void pop(){
heap[1]=heap[np--];
int x=1,y=2;
while(y<=np){
if(y<np&&heap[y]<=heap[y+1]) y++;
if(heap[x]<heap[y]) swap(heap[x],heap[y]),x=y,y*=2;
else break;
}
}
int main(){
scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
for(int i=1;i<=n;i++)
scanf("%d",&k),push(k);
for(int i=0;i<m;i++){
k=heap[1]+i*q,pop();
if((i+1)%t==0) printf("%d ",k);
int tmp=(long long)u*k/v;
push(tmp-q*i-q),push(k-tmp-q*i-q);
}
printf("\n");
for(int i=1;i<=m+n;i++){
if(i%t==0) printf("%d ",heap[1]+q*m);
pop();
}
return 0;
}
100分代码:(多个队列维护实现)
#include<cstdio>
#include<cstring>
#include<queue>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=10000000;
int n,m,q,u,v,t,k,pos,mx;
int que[3][maxn],front[3],rear[3];
#define push(i,var) que[i][rear[i]++]=(var)
#define pop(i) front[i]++
#define front(i) que[i][front[i]]
bool empty(int i){
return rear[i]==front[i];
}
bool cmp(int x,int y){return x>y;}
int out[15];
void scan(int &sca){
char ch=getchar();
while(!isdigit(ch))ch=getchar();
sca=0;
while(isdigit(ch)) sca=sca*10+ch-'0',ch=getchar();
}
void print(int pnt){
int p=0;
if(pnt==0) {putchar('0');return;}
else while(pnt){out[p++]=pnt%10;pnt/=10;}
for(int j=p-1;j>=0;j--) putchar('0'+out[j]);
}
int main(){
// freopen("in.in","r",stdin);
// freopen("ans2.out","w",stdout);
scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
for(int i=0;i<n;i++) scan(que[0][i]);
sort(que[0],que[0]+n,cmp);
rear[0]=n;
for(int i=0;i<m;i++){
for(int j=0;j<3;j++) if(!empty(j)) {pos=j;break;}
if(!empty(0)&&front(0)>front(pos)) pos=0;
if(!empty(1)&&front(1)>front(pos)) pos=1;
if(!empty(2)&&front(2)>front(pos)) pos=2;
k=front(pos)+i*q,pop(pos);
if((i+1)%t==0) print(k),putchar(' ');
int tmp=(long long)k*u/v;
push(1,tmp-q*i-q);
push(2,k-tmp-q*i-q);
}
putchar('\n');
for(int i=1;i<=n+m;i++){
mx=-0x7ffffffa;
for(int j=0;j<3;j++) if(!empty(j)&&front(j)>mx)
mx=front(j),pos=j;
pop(pos);
if(i%t==0) print(mx+m*q),putchar(' ');
}
return 0;
}
T3:愤怒的小鸟
考察知识:状态压缩,搜索
算法难度:XXXX 实现难度:XXX+
分析:
我之前尝试用搜索解决,但是我的方法只有90分,超时的两个点每个需要2分钟才出答案,于是我放弃了用搜索解决,参考了P2831 愤怒的小鸟 题解(特别是用dp算法的第一篇题解)中的状态压缩的解法。
定义状态方程:表示消灭集合A中所有的猪需要的最少小鸟数
状态转移方程:
,其中表示按消灭猪 i,j 的轨迹可以消灭的猪的集合
,其中表示一只猪 i 的集合
边界:
时间复杂度:,面对大数据会超时
优化:
我们发现状态转移的顺序不影响结果,所以我们让转移顺序唯一,这样可以减少转移次数
设表示的最小 i 值
对于每次集合 A 的转移,我们转移 即可
这样每次转移的时间复杂度从降到了,总时间复杂度为:
代码:(个人觉得比较容易看懂,就没有加注释)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const double eps=0.0000001;
double x[20],y[20];
int f[1<<18],bit_[1<<18],pig[20][20],n,m,T;
void solve(){
memset(f,1,sizeof(f));
memset(pig,0,sizeof(pig));
f[0]=0;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++) if(fabs(x[i]-x[j])>eps){
double a_=(y[i]*x[j]-x[i]*y[j])/((x[i]*x[j])*(x[i]-x[j]));
if(a_>0.0) continue;
double b_=(x[j]*x[j]*y[i]-x[i]*x[i]*y[j])/((x[i]*x[j])*(x[j]-x[i]));
for(int t=0;t<n;t++) if(fabs(y[t]-x[t]*(a_*x[t]+b_))<eps)
pig[i][j]+=1<<t;
pig[j][i]=pig[i][j];
}
for(int i=0;i<(1<<n);i++){
int t=bit_[i];
f[i|(1<<t)]=min(f[i|(1<<t)],f[i]+1);
for(int j=0;j<n;j++)
f[i|pig[t][j]]=min(f[i|pig[t][j]],f[i]+1);
} printf("%d\n",f[(1<<n)-1]);
}
int main(){
for(int i=(1<<18)-1;i>=0;i--){
int t=0;
while(t<18&&i&(1<<t)) t++;
bit_[i]=t;
}
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%lf%lf",x+i,y+i);
solve();
}
return 0;
}