題目
3808,3809,3810
失分小結
估分
100+40+10
(第三題切分切太多dfs沒寫…)
實際分數
100+20+30
第二題炸了其實最好能寫到80
題解
T1
P100
我是直接敲P100代碼實話說我還真不知道P70怎麼寫…
//加讀入掛16ms,不加30ms
CODE
#include<cstdio>
#define N 200005
typedef long long LL;
const LL P=1e9+7;
int A[N];//數組還可以優化
inline void rd(int &x) {
x=0;char c;
while(c=getchar(),c<48);
do x=(x<<3)+(x<<1)+(c&15);
while(c=getchar(),c>47);
}
int main() {
int n;
rd(n);
for(int i=0; i<=n; i++)rd(A[i]);
LL sum=(A[0]+A[1])%P;
LL res=(2LL*A[0]*A[1])%P;
LL POW=1;
for(int i=2; i<=n; i++) {
POW=(POW<<1)%P;
res=(((res+sum*A[i])%P)<<1)%P;
sum=(sum+A[i]*POW)%P;
}
printf("%lld\n",res);
return 0;
}
T2
平面圖上的MST.
普通MST可以寫到P40,但是由於平面圖的特殊性,可以進行各種優化.
P70-80
CODE
#include<cstdio>
#include<cmath>
#include<algorithm>
#define FOR(i,a,b) for(int i=(a),i##_end_=(b);i<=i##_end_;i++)
#define M 1000005
using namespace std;
typedef long long LL;
int Y1[M],Y2[M],fa[M*2];
LL Sum1[M],Sum2[M];
struct node {
int x,y;
double len;
} E[5*M];
template<class T>void rd(T &x) {
x=0;static char p;
while(p=getchar(),p<48);
do x=(x<<1)+(x<<3)+(p&15);
while(p=getchar(),p>47);
}
bool cmp(node w1,node w2) {return w1.len<w2.len;}
double ans=0;
LL sqr(LL x) {return x*x;}
int getfa(int x) {return fa[x]==x?x:fa[x]=getfa(fa[x]);}
int main() {
int n,m,x1,x2,tot=0;
rd(n),rd(m),rd(x1),rd(x2);
FOR(i,1,n)rd(Y1[i]),Sum1[i]=Sum1[i-1]+Y1[i];
FOR(i,1,m)rd(Y2[i]),Sum2[i]=Sum2[i-1]+Y2[i];
int tmp=sqr(x1-x2);
FOR(i,1,n-1)E[++tot]=(node) {i,i+1,Y1[i+1]};
FOR(i,1,m-1)E[++tot]=(node) {n+i,n+i+1,Y2[i+1]};
FOR(i,1,n) {
int id=lower_bound(Sum2+1,Sum2+1+m,Sum1[i])-Sum2;
if(id==m+1)id--;
if(Sum2[id]==Sum1[i])E[++tot]=(node) {i,n+id,x2-x1};
else if(Sum2[id]<Sum1[i])E[++tot]=(node) {
i,n+id,sqrt(tmp+sqr(Sum1[i]-Sum2[id]))};
else {
E[++tot]=(node) {i,n+id,sqrt(tmp+sqr(Sum1[i]-Sum2[id]))};
id--;
if(!id)continue;
E[++tot]=(node) {i,n+id,sqrt(tmp+sqr(Sum1[i]-Sum2[id]))};
}
}
sort(E+1,E+1+tot,cmp);
FOR(i,1,n+m)fa[i]=i;
FOR(i,1,tot) {
int x=getfa(E[i].x),y=getfa(E[i].y);
if(x==y)continue;
ans+=E[i].len;
fa[x]=y;
}
printf("%.2f\n",ans);
return 0;
}
P100
顯然最簡(bian)單(tai)的還是
定義
轉移方程見CODE.
維護
顯然
CODE
#include<cstdio>
#include<cmath>
#include<algorithm>
#define M 1000005
using namespace std;
template<typename T>void rd(T &x) {
x=0;static char c;
while(c=getchar(),c<48);
do x=(x<<3)+(x<<1)+(c&15);
while(c=getchar(),c>47);
}
int Y1[M],Y2[M];
double f[M][2][2];
int n,m;
long long x1,x2,x;
double t;
inline long long sqr(register int x){return 1LL*x*x;}
inline double dist(int i,int j) {return sqrt(x+sqr(Y1[i]-Y2[j]));}
int main() {
rd(n),rd(m),rd(x1),rd(x2);
x=sqr(x1-x2);
for(int i=1; i<=n; i++) {
rd(Y1[i]);
if(i>1)Y1[i]=Y1[i]+Y1[i-1];
}
for(int i=1; i<=m; i++) {
rd(Y2[i]);
if(i>1)Y2[i]=Y2[i]+Y2[i-1];
}
f[1][1][1]=dist(1,1);
int j=1,cur=1;
for(int i=1; i<=n; i++) {
if(i>1) {
t=dist(i,j);
f[i][cur][1]=min(f[i-1][cur][1]+Y1[i]-Y1[i-1],min(f[i-1][cur][1]+t,f[i-1][cur][0]+Y1[i]-Y1[i-1]+t));
f[i][cur][0]=min(f[i-1][cur][1],f[i-1][cur][0]+Y1[i]-Y1[i-1]);
}
while(j<m&&(Y1[i]>=Y2[j]||i==n)) {
t=dist(i,++j);
cur=!cur;
f[i][cur][1]=min(f[i ][!cur][1]+Y2[j]-Y2[j-1],min(f[i][!cur][1]+t,f[i][!cur][0]+Y2[j]-Y2[j-1]+t));
f[i][cur][0]=min(f[i ][!cur][1],f[i][!cur][0]+Y2[j]-Y2[j-1]);
}
}
printf("%.2lf\n",f[n][m&1][1]);
return 0;
}
T3
P10
P30
P50
CODE
#include<cstdio>
#include<memory.h>
#include<cmath>
#define S 20
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
using namespace std;
template<typename T>inline void Rd(T &x) {
x=0;
register char c;
while(c=getchar(),c<48);
do x=(x<<3)+(x<<1)+(c&15);
while(c=getchar(),c>47);
}
int n,m,P;
int B[35];
bool mark[S];
int dp[S][1<<S];
int main() {
scanf("%d%d%d",&n,&m,&P);
FOR(i,1,m) {
int x,pos;
scanf("%d%d",&x,&pos);
mark[x]=1;
B[x]=pos;
B[x]--;
}
int tot=(1<<n)-1;
memset(dp,-1,sizeof dp);
dp[0][0]=1;
FOR(k,1,n)FOR(i,0,tot)if(~dp[k-1][i])
FOR(j,B[k],n-1)if(!(i&(1<<j))) {
if(!~dp[k][i|(1<<j)])
dp[k][i|(1<<j)]=0;
dp[k][i|(1<<j)]+=dp[k-1][i];
dp[k][i|(1<<j)]%=P;
if(mark[k])break;
}
printf("%d\n",dp[n][tot]==-1?0:dp[n][tot]);
return 0;
}
P60
這裏加上了P50的代碼
CODE
#include<cstdio>
#include<cstdlib>
#include<memory.h>
#include<algorithm>
#define FOR(i,a,b) for(int i=(a),i##_END_=(b);i<=i##_END_;i++)
#define N 35
#define S 20
using namespace std;
int peo[N];
struct node {
int p,q;
bool operator<(const node _)const {return p<_.p;}
} A[N];
template<typename T>inline void Rd(T &x) {
x=0;register char c;
while(c=getchar(),c<48);
do x=(x<<3)+(x<<1)+(c&15);
while(c=getchar(),c>47);
}
int B[N];
bool mark[S];
int dp[S][1<<S];
int main() {
int n,m,M;
scanf("%d %d %d",&n,&m,&M);
if(m==0) {
long long ans=1;
for(int i=2; i<=n; i++)
ans=(ans*i)%M;
printf("%lld\n",ans);
exit(0);
}
if(m==1) {
long long f[N],A[N],ans=0;
int p,q;
scanf("%d %d",&p,&q);
A[0]=f[0]=f[1]=1,A[1]=p-1;
for(int i=2; i<=n; i++) {
f[i]=(f[i-1]*i)%M;
A[i]=(A[i-1]*(p-i))%M;
}
for(int i=0; i<=min(p-1,n-q); i++) {
ans=(ans+A[i]*f[n-1-i])%M;
}
printf("%lld\n",ans);
exit(0);
}
FOR(i,1,m) {
int x,pos;
scanf("%d%d",&x,&pos);
mark[x]=1;
B[x]=pos;
B[x]--;
}
int tot=(1<<n)-1;
memset(dp,-1,sizeof dp);
dp[0][0]=1;
FOR(k,1,n)FOR(i,0,tot)if(~dp[k-1][i])
FOR(j,B[k],n-1)if(!(i&(1<<j))) {
if(!~dp[k][i|(1<<j)])
dp[k][i|(1<<j)]=0;
dp[k][i|(1<<j)]+=dp[k-1][i];
dp[k][i|(1<<j)]%=M;
if(mark[k])break;
}
printf("%d\n",dp[n][tot]==-1?0:dp[n][tot]);
return 0;
}
P100
首先有一個比較顯然的性質:若第
而由於可以通過可行性剪枝剪掉很多不合法的情況,
另外,由於
CODE
#include<cstdio>
#include<memory.h>
#include<algorithm>
#define N 35
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
int n,m,M;
struct node {int p,q;} D[10];
int C[N][N],fac[N],A[N][N];
bool mark[N];
int ans;
bool cmp(node _,node __){return _.p<__.p;}
int x=1;
void dfs(int res,int tmp) {
res+=D[x].p-D[x-1].p-1;
if(x>m) {
tmp=1ll*tmp*fac[res]%M;
ans=(ans+tmp)%M;
return;
}
int sum=0;
bool used[N];
memcpy(used,mark,sizeof used);
for(int i=D[x].q; i<=n; i++)if(!mark[i]) {
if(sum>res)break;
mark[i]=1;
x++,dfs(res-sum,1ll*tmp*A[res][sum]%M),x--;
sum++;
}
memcpy(mark,used,sizeof mark);
}
int main() {
scanf("%d%d%d",&n,&m,&M);
FOR(i,1,m)scanf("%d%d",&D[i].p,&D[i].q);
C[0][0]=C[1][0]=C[1][1]=fac[0]=fac[1]=1;
FOR(i,2,30) {
C[i][0]=C[i][i]=1;
fac[i]=1ll*fac[i-1]*i%M;
FOR(j,1,i-1)C[i][j]=(C[i-1][j]+C[i-1][j-1])%M;
}
FOR(i,0,30)FOR(j,0,i)A[i][j]=1LL*C[i][j]*fac[j]%M;
std::sort(D+1,D+1+m,cmp);
D[m+1].p=n+1;
D[0].p=0;
dfs(0,1);
printf("%d\n",ans);
return 0;
}