#include
using namespace std;
int a[10010][10010];
int n,x,y;
bool flag;
int main(){
// freopen("carpet.in","r",stdin);
// freopen("carpet.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i][0]>>a[i][1]>>a[i][2]>>a[i][3];
a[i][2]+=a[i][0];
a[i][3]+=a[i][1];
}
cin>>x>>y;
for(int i=n;i>=1;i--){
if(a[i][0]<=x && a[i][1]<=y && a[i][2]>=x && a[i][3]>=y)
{
cout<
T2
想了半天正解还是降不下来时间复杂度,最后直接打了个三重循环暴力,一层1客栈,二层2客栈,3层合理的位置,拿了60分,其实只需要小小的优化就可以去掉两重循环了。
60代码
#include
using namespace std;
int flag[200010],c[200010],b[200010],sum[200010];
int n,m,x;
int ans;
int main(){
// freopen("hotel.in","r",stdin);
// freopen("hotel.out","w",stdout);
cin>>m>>n>>x;
for(int i=1;i<=m;++i){
scanf("%d%d",&b[i],&c[i]);
sum[b[i]]++;
if(c[i]<=x) flag[i]=1;
}
for(int i=1;i<=m;++i){
if(flag[i]) {
ans+=sum[b[i]]-1;
sum[b[i]]--;
continue;
}
for(int j=i+2;j<=m;++j){
if(b[i]==b[j] && !flag[j]){
for(int k=i+1;k
只需要枚举第二个客栈,然后用第二个客栈反推出前面的方案数。就是,从1到n枚举,记录一个距离第二个客栈最近的咖啡厅价钱合理的客栈位置,用now记录。如果我发现枚举的时候在某一个客栈前面有一个价钱合理的咖啡厅,那么在这之前的任何一个同色客栈都是这个客栈可以选的。
100代码
#include
using namespace std;
int cnt[10001],sum[10001],last[10001];
int n,m,x,a,b,now,ans;
int main(){
cin>>n>>m>>x;
for(int i=1;i<=n;i++){
cin>>a>>b;
if(b<=x){
now=i;
}
if(now>=last[a]){
sum[a]=cnt[a];
}
last[a]=i;
ans+=sum[a];
cnt[a]++;
}
cout<
T1
用f[i][j]表示x^i y^j的系数,可以得到转移f[i][j]=f[i-1][j]*a+f[i][j-1]*b,然后注意一下初始化。
#include
using namespace std;
#define mo 10007
int n,m,a,b,k;
long long dp[10001][10001];
int main(){
// freopen("factor.in","r",stdin);
// freopen("factor.out","w",stdout);
cin>>a>>b>>k>>n>>m;
dp[0][0]=1;
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
if(!j && !i ) continue;
if(i){
dp[i][j]+=dp[i-1][j]*a%mo;
}
if(j){
dp[i][j]+=dp[i][j-1]*b%mo;
}
dp[i][j]%=mo;
}
}
cout<
T2
这道题其实很明显的二分,显然我们无法直接算出W的值,只能枚举W,比较Y与S的大小,然后缩减枚举范围。(然后打了个超级暴力还打错了)另一个就是前缀和。因为区间很多,而且区间范围也很大,所以我们先预处理出所有sum[i],然后要求l[i]到r[i]的区间,只需求sum[r[i]]-sum[l[i]-1]。
#include
#include
using namespace std;
typedef long long LL;
const int N=200100;
LL ans=1e15;
LL sw[N],sv[N],w[N],v[N];
int l[N],r[N];
int n,m;
LL S;
LL f(LL a,LL b){
return a>b?a-b:b-a;
}
bool check(LL mid){
for (int i=1;i<=n;i++){
sw[i]=sw[i-1]+(w[i]>=mid);
sv[i]=sv[i-1]+(w[i]>=mid)*v[i];
}
LL W=0;
for (int i=1;i<=m;i++){
W+=(sw[r[i]]-sw[l[i]-1])*(sv[r[i]]-sv[l[i]-1]);
}
ans=min(ans,f(W,S));
return W<=S;
}
int main(){
scanf("%d%d%lld",&n,&m,&S);
LL Left=0,Right=0;
for (int i=1;i<=n;i++){
scanf("%lld%lld",&w[i],&v[i]);
Right=max(Right,w[i]);
}
Right++;
for (int i=1;i<=m;i++){
scanf("%d%d",&l[i],&r[i]);
}
while (Left+1>1;
if (check(mid))Right=mid;
else Left=mid;
}
check(Left);check(Right);
printf("%lld",ans);
return 0;
}
T3
有点玄学的贪心,首先,我们要所有旅客的旅行时间最小,那么在加加速器的时候,肯定要选择一条旅客经过的数量最多的那条路,然后,由于某些乘总是很迟到达一个站点,如果这个乘客实在到达得太迟,比公交车到达这个站点的时间更迟的话,那么我们就不用在这条边上加加速器了,因为即使加了你也要等到乘客来了才能走,这显然不是最优解。
#include
using namespace std;
int d[20001], getto[20001], getoff[20001], latest[20001], f[20001];
//d[i]:i - i+1这条边的长
//latest[i]:最晚到达i点的人的到达时间
//getto[i]:公交车到达i点的时间
//getoff[i]:在i点下车的人数
//f[i]:i - i+1这条边最多能减少多少时间
struct Passenger{
int t, s, e;
}a[20001];
int n, m, k;
int main(){
cin>>n>>m>>k;
for(int i=1;i>d[i];
for (int i=1;i<=m;i++){
cin>>a[i].t>>a[i].s>>a[i].e;
latest[a[i].s]=max(latest[a[i].s],a[i].t);
getoff[a[i].e]++;
}
for (int i=1;i<=n;i++)
getto[i]=max(getto[i-1],latest[i-1])+d[i-1];
while (k --){
for (int i=n;i>=2;i--)
if (!d[i-1]) f[i-1]=0;
else{
f[i-1]=getoff[i];
if (getto[i]>latest[i]) f[i-1]=f[i-1]+f[i];
}
int maxtime=0,pos=0;
for (int i=1;imaxtime){
maxtime=f[i];
pos=i;
}
if (pos==0) break;
d[pos]--;
for (int i=pos+1;i<=n;i++)
getto[i]=max(getto[i-1],latest[i-1])+d[i-1];
}
int tot=0;
for (int i=1;i<=m;i++)
tot+=getto[a[i].e]-a[i].t;
cout<