题目链接
B-Brownie Slicing
题意:给你一个n*m 的带权矩阵,现在给你 r c 要求每行分成 r 份,每份单独列切 分成 c 份,每份的美味值等于带权矩阵中的矩阵和,现在问你如何切 使得最小的 那份蛋糕 权值最大。
做法:二分 最小蛋糕 权值最大即可,然后check一下能否切r 行 c列份,区间和就是二维前缀和就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e2+10;
ll a[N][N],sum[N][N];
int n,m,x,y;
ll run(int l1,int r1,int l2,int r2)
{
return sum[l2][r2]-sum[l2][r1-1]-sum[l1-1][r2]+sum[l1-1][r1-1];
}
int cal(ll mid)
{
int l1,r1,l2,r2;
l1=0,r1=1,l2=0,r2=1;
int t=0;
while(l2<=n){
int num=0;//每一行
l1=l2+1,r1=r2=1,l2=l1;
while(l1<=n&&l2<=n){
num=0;
for(int r2=1;r2<=m&&r1<=m;++r2){
if(run(l1,r1,l2,r2)>=mid) {
num++,r1=r2+1;
}
}
if(num>=y) {
t++;
break;
}
else {
l2++;
r1=r2=1;
}
}
}
return t>=x;
}
int main()
{
cin>>n>>m>>x>>y;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
scanf("%lld",&a[i][j]);
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
}
}
ll l=0,r=1e9,ans=0;
while(l<=r){
ll mid=l+r>>1;
if(cal(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%lld\n",ans);
return 0;
}
E-Best Parenthesis
题意:给你一行 括号已经匹配的字符串,
一个 () 权值为1,有一个嵌套的就乘上2 例:(()) =2 ((())(()))=8
做法:普通栈模拟下就可以了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=12345678910;
const int N=1e5+10;
int n;
stack<ll>sta;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i){
ll x;
scanf("%lld",&x);
if(x==0) x=-1;
else x=-2;
if(x==-1) sta.push(-1);
else {
if(sta.top()==-1) sta.pop(),sta.push(1);
else{
ll d=0;
while(sta.top()!=-1){
d=d+sta.top();sta.pop();
d%=mod;
}
sta.pop();
sta.push(d*2%mod);
}
}
}
ll ans=0;
while(sta.size()) {
ans+=sta.top(),sta.pop();
ans%=mod;
}
printf("%lld\n",ans);
}
F-Cow Line
题意:现在,已知N头牛的排列方式,求这种排列方式的行号。
或者已知行号,求牛的排列方式。
所谓行号,是指在N头牛所有可能排列方式,按字典顺序从大到小排列后,某一特定排列方式所在行的编号。
如果,行号是3,则排列方式为1 2 4 3 5
如果,排列方式是 1 2 5 3 4 则行号为5
有K次问答,第i次问答的类型,由C_i来指明,C_i要么是‘P’要么是‘Q’。
当C_i为P时,将提供行号,让你答牛的排列方式。当C_i为Q时,将告诉你牛的排列方式,让你答行号。
做法:这是一个康托展开和康托逆展开的裸题,这个很简单
学习博客
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=22;
ll f[N],a[N],b[N];
int n,q,vis[N];
ll cal1()
{
ll res=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;++i){
int num=0;
for(int j=a[i]-1;j>=1;--j){
if(vis[j]==0) num++;
}
//printf("num:%d f:%lld\n",num,f[n-i]);
res=res+f[n-i]*num;
vis[a[i]]=1;
}
return res+1;
}
void cal2(ll x)
{
memset(vis,0,sizeof(vis));
int l=n-1;
int len=1;
while(len<=n){
int t=x/f[l],i=1;
x=x%f[l];
for(;i<=n;++i){
if(vis[i]==0) {
if(t) --t;
else break;
}
}
vis[i]=1;
b[len]=i;
++len,--l;
}
for(int i=1;i<=n;++i) printf("%lld ",b[i]);
puts("");
}
int main()
{
f[0]=1;
for(int i=1;i<N;++i) f[i]=f[i-1]*i;
scanf("%d%d",&n,&q);
while(q--){
char s;
cin>>s;
if(s=='P'){
ll x;
cin>>x;
cal2(x-1);
}
else{
for(int i=1;i<=n;++i){
cin>>a[i];
}
printf("%lld\n",cal1());
}
}
}
J-Cowlphabet
题意:输入u,l,p p行2长度的字符串 要你构造一个字符串 含有u个大写,l个小写 且任意相邻的字符串都是p中的一种。
做法:dp即可,dp[i][j][k] 代表构造的前i个字符含有j个小写,且末尾字符是k的方案数 大写数==i-j 省略了一维,然后稍微搞搞就行了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=260;
const ll mod=97654321;
ll dp[2*N][N][53];
int u,l,n;
string s[N];
int get(char x)
{
if('a'<=x&&x<='z') return x-'a'+1;
return x-'A'+27;
}
int check(int x)
{
if(1<=x&&x<=26) return 1;
return 0;
}
int main()
{
cin>>u>>l>>n;
for(int i=1;i<=n;++i){
cin>>s[i];
int t0=get(s[i][0]),t1=get(s[i][1]);
int x=0;
if(check(t0)) x++;
if(check(t1)) x++;
dp[2][x][t1]++;
}
for(int i=3;i<=u+l;++i){
for(int j=0;j<=l;++j){
for(int k=1;k<=n;++k){
int t0=get(s[k][0]),t1=get(s[k][1]);
if(dp[i-1][j][t0]==0) continue;
int x=0;
if(check(t1)) x++;
dp[i][j+x][t1]+=dp[i-1][j][t0];
dp[i][j+x][t1]%=mod;
}
}
}
ll ans=0;
for(int i=1;i<=52;++i) ans+=dp[u+l][l][i],ans%=mod;
printf("%lld\n",ans);
}
L-Dividing the Gold
题意翻译
Bessie 和 Canmuu 发现了一个有 N 个金币的袋子(1 <= N <= 250) 。第i个金币有一个价值 Vi (1 <= Vi <= 2000)他们希望尽可能的把这堆金币平均分配,但有时这是不可能的。找出使两堆价值差最小的分配方案。如果不能完全平均分开,Bessie会获得较高价值那一堆。
方案数就是01 背包中把最初始的状态dp[0]=1 然后再跑一遍刚刚的转移方程就可以了
#include<bits/stdc++.h>
#define mod 1000000
using namespace std;
int n,a[350],tot,sum,f[500005];
long long dp[500005];
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=read(),sum+=a[i];
tot=sum;
sum/=2;
for(int i=1;i<=n;i++)
for(int j=sum;j>=a[i];j--)
f[j]=max(f[j],f[j-a[i]]+a[i]);
printf("%d\n",tot-2*f[sum]);
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=tot;j>=a[i];j--)
dp[j]=(dp[j]+dp[j-a[i]])%mod;
printf("%lld",dp[f[sum]]);
return 0;
}