NOIP模拟3
原 A层联测28 请走 CSP-S 模拟 10、13
下发文件
三元
一个简单的构造. 让最大的尽可能小,那就一定是形如 2 + 0...0 + 1/2...1/2
样子的数. 那就对应去构造这样的数,每一种一共有 n 个,那么就是一个三进制加法,从 2000...00
往上加即可.
直接加不优秀,那么就可以对它进行构造. 直接将每一相同数位的后面不断分裂. 然后类似地其他数也这么构造,注意别多了就行.
点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 50001
#define ld long double
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,L,mx;
short ans[3][maxn][16];
int main()
{
freopen("three.in","r",stdin); freopen("three.out","w",stdout);
n=read();L=read()-1;mx=L-__builtin_ceill(__builtin_log2l(n)/__builtin_log2l(3));
// cout<<n<<' '<<L<<' '<<mx<<endl;
// for(rll i=1;i<=mx;i++) for(rll j=1;j<=n;j++) ans[2][j][i]=0;
// assert(!ans[2][10][1]);
for(rll i=mx+1,t=__builtin_powl(3,L-mx-1);i<=L;i++,t/=3)
{
for(rll j=0;j<n;j++) /*cout<<i<<' '<<j<<endl,*/ans[2][j+1][i]=(j/t)%3;
// cout<<t<<endl;write(i);putn;assert(!ans[2][10][1]);
}
for(rll i=1;i<=mx;i++) for(rll j=1;j<=n;j++) ans[0][j][i]=2;
for(rll i=mx+1,t=__builtin_powl(3,L-mx-1);i<=L;i++,t/=3) for(rll j=0;j<n;j++) ans[0][j+1][i]=(j/t+2)%3;
for(rll i=1;i<=mx;i++) for(rll j=1;j<=n;j++) ans[1][j][i]=1;
for(rll i=mx+1,t=__builtin_powl(3,L-mx-1);i<=L;i++,t/=3) for(rll j=0;j<n;j++) ans[1][j+1][i]=(j/t+1)%3;
// cout<<endl;assert(!ans[2][10][1]);
for(rll i=0;i<3;i++) for(rll k=1;k<=n;k++) { write(i); for(rll j=1;j<=L;j++) write(ans[i][k][j]); putn; }
return 0;
}
鹅国
看到这玩意就往 dp 上去想,准没错. 首先最简单的背包就不说了.
然后,可以设 dp[0/1][j][k] 表示已选中 j 个,当前这次选了 k 个的最小和最大的重量.
转移时,枚举每一个硬币和 j、k,然后再枚举一层,用来表示当前这些硬币能否用更小的来替换,是否对答案有贡献. 有则转移取最值.
因为每一轮不能更改上一轮的状态,所以用一个滚动数组. 处理答案的时候为了方便多转移一次到 k + 1 处. 最后把整个答案和上一轮的答案与最小的那个硬币组合取一个最值(其实是可以放到转移里面的...).
不是正解,但是 n × k3 足以通过本题.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 1001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,k,p,c[maxn],w[maxn],dp[2][2][maxn][maxn],mo,ans1,ans2;
bool pp;
int main()
{
freopen("goose.in","r",stdin); freopen("goose.out","w",stdout);
n=read();k=read();p=read(); for(rll i=1;i<=n;i++) c[i]=read(),w[i]=read();
// cout<<p<<' '<<c[1]<<endl;
assert(c[1]);
if((p%c[1])||p/c[1]<k||p/c[n]>k) { puts("-1");return 0; } p/=c[1]; for(rll i=n;i;i--) c[i]/=c[1];
memset(dp[1][0],0b00111111,sizeof(dp[1][0])); memset(dp[1][1],0b11000000,sizeof(dp[1][1]));
assert(c[n]);
dp[1][0][p/c[n]][p/c[n]]=dp[1][1][p/c[n]][p/c[n]]=0;
for(rll i=n;i;i--)
{
memset(dp[pp][0],0b00111111,sizeof(dp[pp][0])); memset(dp[pp][1],0b11000000,sizeof(dp[pp][1])); mo=p%c[i];
for(rll j=1,t;j<=k;j++) for(rll l=0;l<=k;l++) if(!(dp[pp^1][1][j][l]&LLONG_MIN)) for(rll m=0;m<=l;m++)
{
// cout<<i<<' '<<c[i]<<' '<<c[i-1]<<endl; assert(c[i-1]);
if(i^1) t=(c[i]/c[i-1])*m+mo/c[i-1]; else t=0;
if(t+j-m<=k) dp[pp][0][j-m+t][t]=min(dp[pp][0][j-m+t][t],dp[pp^1][0][j][l]+(l-m)*w[i]),
dp[pp][1][j-m+t][t]=max(dp[pp][1][j-m+t][t],dp[pp^1][1][j][l]+(l-m)*w[i]);
}
pp^=1;
}
ans1=dp[pp^1][0][k+1][0],ans2=dp[pp^1][1][k+1][0];
for(rll i=0;i<=k;i++) ans1=min(ans1,dp[pp^1][0][k][i]+w[1]*i),ans2=max(ans2,dp[pp^1][1][k][i]+w[1]*i);
if(ans1==0b0011111100111111001111110011111100111111001111110011111100111111) { puts("-1"); return 0; }
write(ans1);put_;write(ans2);putn;
return 0;
}
楼盘
不会,没改.
矩形
先拿一个单调栈去求出每一个点它的高度所能延伸的最大值(就是找那个最大的矩形). 我就不写笛卡尔树,谁说单调栈是 n2 的
对于每一个排序后的高度,显然是单调的,因此可以进行二分. 把 L 和 R 对应的数字二分出来,枚举所有的数字,查询其排名不断插入即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 300001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,h[maxn],l,r,posl,posr,mx,st[maxn],ed[maxn];
stack<ll> s;
vector<ll> ans;
#define S(x) ((x)<=0?0:(x)*((x)+1)>>1)
#define f(pos,l,r) (S(pos)-S((pos)-(l)-1)-S((pos)-(r)-1)+S((pos)-(l)-(r)-2))
inline bool chk(rll x,rll num)
{
if(x-1<=0) return 1; rll ans=0; for(rll i=1;i<=n;i++) ans+=f(min((x-1)/h[i],ed[i]-st[i]+1),i-st[i],ed[i]-i); return ans<num;
}
inline ll erfen(rll x)
{
rll l=0,r=1000000000000000000,ans=-1; while(l<=r) { rll mid=l+r>>1; if(chk(mid,x)) ans=mid,l=mid+1; else r=mid-1; } assert(~ans); return ans;
}
int main()
{
freopen("rectangle.in","r",stdin); freopen("rectangle.out","w",stdout);
n=read(); for(rll i=1;i<=n;i++) h[i]=read(); l=read();r=read(); s.push(st[1]=1);
for(rll i=2;i<=n;i++) { while((!s.empty())&&h[i]<h[s.top()]) ed[s.top()]=i-1,s.pop(); if(s.empty()) st[i]=1; else st[i]=s.top()+1; s.push(i); }
while(!s.empty()) ed[s.top()]=n,s.pop(); posl=erfen(l),posr=erfen(r);// for(rll i=1;i<=n;i++) cout<<st[i]<<' '<<ed[i]<<endl; cout<<posl<<' '<<posr<<endl;
rll t=0; for(rll i=1;i<=n;i++) t+=f(min(posl/h[i],ed[i]-st[i]+1),i-st[i],ed[i]-i); mx=min(t,r);
for(rll i=l;i<=mx;i++) ans.emplace_back(posl);
for(rll i=1,mx,mn,s,t,tot;i<=n;i++)
{
mx=max(ed[i]-i+1,i-st[i]+1),mn=min(ed[i]-i+1,i-st[i]+1),s=posl/h[i]+1,t=min(ed[i]-st[i]+1,(posr-1)/h[i]);
for(rll j=s;j<=t;j++)
{
if(j<=mn) tot=j; else if(j<=mx) tot=mn; else tot=ed[i]-st[i]-j+2; while(tot--) ans.emplace_back(j*h[i]);
}
}
while(ans.size()<r-l+1) ans.emplace_back(posr); sort(ans.begin(),ans.end()); for(rll i=0;i<ans.size();i++) write(ans[i]),put_;
return 0;
}
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16893737.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!