第一题:饼干
题意:有一(2^n)*(2^n)的矩阵,每次可选一范围2^k使其右上角铺满饼干(k>=2)。求最少有几块不能被覆盖。
题解:自己画图,丰衣足食。(答案即3^(n-1))
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define mod 1000003
using namespace std;
inline int read(){
int i=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch);ch=getchar())
if(ch=='-') f=-1;
for(;isdigit(ch);ch=getchar())
i=(i<<3)+(i<<1)+(ch^48);
return i*f;
}
int n;
long long fast(long long a,long long b){
long long ret=1;
while(b){
if(b&1)
ret=(ret*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ret;
}
signed main(){
n=read();
cout<<fast(3,n-1);
return 0;
}
第二题:鸭舌
题意:n点树,i节点有ai个鸭舌,从给定节点x出发,每到一点该点鸭舌-1,无鸭舌不行,欲返x,求至多能食之舌几何。
题解:大家都知道这必须是一个树形DP,以x为根,能走子树先走子树。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<vector>
using namespace std;
inline int read(){
int i=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch);ch=getchar())
if(ch=='-') f=-1;
for(;isdigit(ch);ch=getchar())
i=(i<<3)+(i<<1)+(ch^48);
return i*f;
}
long long dp[101101],a[101101],mini[101101];
int n,aa,b,tot,nxt[202202],first[101101],goal[202202],x;
void addedge(int a,int b){
++tot;
nxt[tot]=first[a];
first[a]=tot;
goal[tot]=b;
++tot;
nxt[tot]=first[b];
first[b]=tot;
goal[tot]=a;
return ;
}
void dfs(int pos,int fa){
dp[pos]=1;
vector<long long>que;
for(int p=first[pos];p;p=nxt[p])
if(goal[p]!=fa&&a[goal[p]]){
--a[goal[p]];
dfs(goal[p],pos);
if(dp[goal[p]]) que.push_back(dp[goal[p]]);
}
sort(que.begin(),que.end());
for(int i=que.size()-1;a[pos]&&i>=0;--i)
--a[pos],dp[pos]+=que[i]+1;
for(int p=first[pos];a[pos]&&p;p=nxt[p])
if(goal[p]!=fa&&a[goal[p]]){
dp[pos]+=min(a[pos],a[goal[p]])*2;
a[pos]-=min(a[pos],a[goal[p]]);
}
return ;
}
signed main(){
n=read();
for(int i=1;i<=n;++i)
a[i]=read();
for(int i=1;i<n;++i){
aa=read();b=read();
addedge(aa,b);
}
x=read();
dfs(x,0);
cout<<dp[x]-1;
return 0;
}
第三题:路径
题意:n*m图,有障碍,障碍周围8格无障碍,每行每列仅一障碍,求两点距离之平均。
题解:见代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define int long long
#define double long double
using namespace std;
inline int read(){
int i=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch);ch=getchar())
if(ch=='-') f=-1;
for(;isdigit(ch);ch=getchar())
i=(i<<3)+(i<<1)+(ch^48);
return i*f;
}
int n,m,transverse[1010],vertical[1010],robl,squ;
double ans;
char s[1010][1010];
long long cal(int n,int m,int *se){
int ret=0;
for(int i=1;i<=n;++i){
int plus=0,place=m-se[i];
for(int j=1;j<=n;++j)
if(i!=j){
if(se[j])plus+=(long long)(m-1)*abs(i-j);
else plus+=(long long)m*abs(i-j);
}
if(se[i]) ret+=plus*(m-1);
else ret+=plus*m;
int lef=i-1,righ=i+1;
if(se[i]){
while(se[lef]>se[lef+1]){
place+=m-se[lef];
--lef;
}
while(se[righ]>se[righ+1]){
place+=m-se[righ];
++righ;
}
ret+=4*(se[i]-1)*place;
}
}
return ret;
}
signed main(){
n=read();m=read();
for(int i=1;i<=n;++i)
scanf("%s",s[i]+1);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(s[i][j]=='X'){
transverse[i]=j;
vertical[j]=i;
++robl;
}
squ=n*m-robl;
ans=(double)(cal(n,m,transverse)+cal(m,n,vertical))/(squ*squ);
printf("%.6Lf",ans);
return 0;
}