题目链接
输入n,m,k;
在n行m列的矩阵中找出每一个k*k的矩阵中最大的数相加。
A{i,j} = lcm(i, j):矩阵的元素为行和列的最小公倍数。
思路:滑动窗口。
代码:
#include
#include
#include
#include
using namespace std;
const int maxn=5010;
int a[maxn][maxn],ans[maxn][maxn];
deque<int> win(maxn);
int lcm(int x,int y)
{
return y?lcm(y,x%y):x;
}
void f(int n, int len, int *arr, int *ans)
{
win.clear();
for(int i=1; i<=n; i++)
{
while(!win.empty()&&arr[win.back()]<arr[i])
win.pop_back();
while(!win.empty()&&win.front()<i-len+1)
win.pop_front();
win.push_back(i);
if(i+1>=len)
ans[i-len+1]=arr[win.front()];
}
}
int main()
{
ios::sync_with_stdio(false);
int n,m,k,i,j;
cin>>n>>m>>k;
if(n>m)
{
int t;
t=n,n=m,m=t;
}
for(i=1; i<=n; i++)
for(j=i; j<=m; j++)
{
int t=i*j/lcm(i,j);
a[i][j]=a[j][i]=t;
}
for(int i=1; i<=n; i++)
f(m,k,a[i],ans[i]);
for(int i=1; i<=m; i++)
{
win.clear();
for(int j=1; j<=n; j++)
{
while(!win.empty()&&ans[win.back()][i]<ans[j][i])
win.pop_back();
while(!win.empty()&&win.front()<j-k+1)
win.pop_front();
win.push_back(j);
if(j+1>=k)
ans[j-k+1][i]=ans[win.front()][i];
}
}
long long result=0;
for(int i=1; i<=n-k+1; i++)
for(int j=1; j<=m-k+1; j++)
result+=ans[i][j];
cout<<result<<endl;
return 0;
}
题目链接
给出每个碗的高、下底半径、上口半径。求出这些碗叠在一起后的最小高度。
数据范围小,可以用枚举
解题思路参考
代码:
#include
#include
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f;
struct Bowl
{
double h,r1,r2,slope;
};
Bowl bowl[20];
double t[20];
int index[20];
double f(Bowl b1,Bowl b2)
{
if(b1.r1>=b2.r2)
return b2.h;
if(b1.r2<=b2.r1)
return 0;
if(b1.slope<=b2.slope)
{
if(b1.r1<=b2.r1)
return 0;
else return (b1.r1-b2.r1)*b2.h/(b2.r2-b2.r1);
}
else{
if(b1.r2>b2.r2)
return max(0.0,b2.h-b1.h*(b2.r2-b1.r1)/(b1.r2-b1.r1));
else return max(0.0,b2.h*(b1.r2-b2.r1)/(b2.r2-b2.r1)-b1.h);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,i,j;
cin>>n;
for(i=0; i<n; i++)
{
cin>>bowl[i].h>>bowl[i].r1>>bowl[i].r2;
bowl[i].slope=(bowl[i].r2-bowl[i].r1)/bowl[i].h;
index[i]=i;
}
double re=0,ans=INF;
do
{
re=0;
for(i=0; i<n; i++)
{
t[i]=0;
for(j=0;j<i;j++)
t[i]=max(t[i],t[j]+f(bowl[index[i]],bowl[index[j]]));
re=max(t[i]+bowl[index[i]].h,re);
}
ans=min(ans,re);
}
while(next_permutation(index,index+n));
cout<<(int)(ans+0.5)<<endl;
return 0;
}
题目描述
有k种油漆,每种油漆可以涂ci个木块, 所有油漆刚好足够涂满所有木块,即c1+c2+…+ck=n。任意两个相邻木块颜色不同的着色方案。
求方案数。
解题思路参考
代码:
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1000000007;
ll t[10];
ll dp[20][20][20][20][20][10];
ll dfs(int a,int b,int c,int d,int e,int w)
{
if(dp[a][b][c][d][e][w]!=-1)
return dp[a][b][c][d][e][w];
if(a+b+c+d+e==0)
return 1;
ll ans=0;
if(a)
ans=(ans+(a-(w==2))*dfs(a-1,b,c,d,e,1))%mod;
if(b)
ans=(ans+(b-(w==3))*dfs(a+1,b-1,c,d,e,2))%mod;
if(c)
ans=(ans+(c-(w==4))*dfs(a,b+1,c-1,d,e,3))%mod;
if(d)
ans=(ans+(d-(w==5))*dfs(a,b,c+1,d-1,e,4))%mod;
if(e)
ans=(ans+e*dfs(a,b,c,d+1,e-1,5))%mod;
return dp[a][b][c][d][e][w] = ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int k,i;
cin>>k;
memset(t,0,sizeof(t));
memset(dp,-1,sizeof(dp));
for(i=0; i<k; i++)
{
int d;
cin>>d;
t[d]++;
}
cout<<dfs(t[1],t[2],t[3],t[4],t[5],0)<<endl;
return 0;
}