11.07练习赛

11.07练习题

T1 俄罗斯套娃

太懒了直接搬原题面系列

你开了一家卖俄罗斯套娃的店。因此,你向厂家订购了\(N\)个俄罗斯套娃,这些娃娃被编号为\(1\)\(N\),其中第\(i\)个套娃是一个的直径为\(R_i\)高度为\(H_i\)的直♂柱体 。每个俄罗斯套娃都只能套高和直径严格比他小的套娃。同时只要满足条件,俄罗斯套娃可以嵌套多次。
 
有一天,你收到了厂家的来电,告诉你你预定的\(N\)个娃娃不能一次性全部做完。所以第一批只会送达直径大于等于\(A\)并且高度小于等于\(B\)的所有套娃。你需要预先安排出一个方案,使送来的套娃经过若干次嵌套后,没有被套的套娃数量最小。
 
由于厂家经常搞大新闻,所以他会改变\(A\)\(B\)的值,总共\(Q\)次,因此你需要对每对\((A,B)\)都作出回答,询问之间互不干扰。

详细题面在此

第一眼看二维数点(实为对wangdy大佬给的数星星印象深刻),于是打了一个维护前缀和的。发现爆了。仔细思考后发现是要维护区间最大值(即为统计最多能套多少个套娃进来)。
稍微改了下,过了。交到OJ上,T了。
那咋办嘛

那就只有快读了啊

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std; 
char *p1,*p2,buf[1<<20]; 
#define GC (p1==p2&&(p1=buf,p2=buf+fread(buf,1,1<<20,stdin),p1==p2)?0:(*(p1++))) 
//#define GC getchar() 
inline int in() 
{ 
    int ans; 
    char t,k; 
    while(((t=GC)!='-'&&(t>'9'||t<'0'))); 
    k=(t=='-'); 
    ans=k?0:(t-'0'); 
    while((t=GC)>='0'&&t<='9')ans=ans*10+t-'0'; 
    return k?-ans:ans; 
}
struct node{
	int r,h;
	int id;
}g[500010],qu[500010];
inline int lowbit(int x){return x&(-x);}
int ans[500010];
int Hs[500010];
bool cmp1(node a,node b){
	return a.h<b.h;
}
bool cmp2(node a,node b)
{
	return a.r<b.r;
}
bool cmp(node a,node b)
{
	if(a.r!=b.r){
		return a.r>b.r;
	}
	return a.h<b.h;
}
int n,q;
int sum[500010];
int gs(int x)
{
	int res=0;
	for(;x;x-=lowbit(x)){
		res=max(res,sum[x]);
	}
	return res;
}
void ins(int x,int k){
	for(;x<=n+q;x+=lowbit(x)){
		sum[x]=max(sum[x],k);
	}
	return;
}
int qh[500010],cnt;//改了半天发现两个东西都要离散化…… 
int main()
{
//	freopen("matryoshka.in","r",stdin);
//	freopen("matryoshka.out","w",stdout);
	n=in();q=in();
	int i,j;
	for(i=1;i<=n;i++)
	{
		g[i].r=in();g[i].h=in();
		qh[++cnt]=g[i].h;
	}
	for(i=1;i<=q;i++)
	{
		qu[i].r=in();qu[i].h=in();
		qu[i].id=i;
		qh[++cnt]=qu[i].h;
	}
	sort(qh+1,qh+cnt+1);
	int cnth=0;
	for(i=1;i<=cnt;i++){
		if(qh[i]!=qh[i-1]){
			Hs[++cnth]=qh[i];
		}
	}
	sort(g+1,g+1+n,cmp);
	sort(qu+1,qu+1+q,cmp);
	j=1;
	for(i=1;i<=q;i++)
	{
		while(g[j].r>=qu[i].r&&j<=n){
			int v=lower_bound(Hs+1,Hs+cnth+1,g[j].h)-Hs;
			ins(v,1+gs(v));
			j+=1;
		}
		int p=lower_bound(Hs+1,Hs+cnth+1,qu[i].h)-Hs;
		ans[qu[i].id]=gs(p);
	}
	for(i=1;i<=q;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}

(注:程序里对于询问操作里\(H\)(即\(B\))值的离散化似乎可以把\(lower\_bound\)改成\(upper\_bound\)优化掉。估计TLE就是因为这个)

T2 帐篷

难以概括(其实就是懒)
原题面在此
 
性感感性理解后发现其实就是每排每列上最多不超过2个帐篷。且若在\((i,j)\)上的帐篷在当前排/列上满足条件后,当前列/排便不能再放帐篷。
所以放帐篷一共有三种情况:(设当前讨论了\(i\)\(j\)列,\(f[i][j]\)方案数)

  1. 仅一个帐篷,则这个帐篷可以取\(4\)个方向,则方案数为\(4*f[i-1][j-1]*C_{j}^1\)
  2. 有两个帐篷,则又有两种情况:
  • \((j\geq2)\):两个帐篷使一行,两列不能再放。则方案数为\(f[i-1][j-2]*C_j^2\)
  • \((i\geq2)\):两个帐篷使两行,一列不能再放,则方案数为:\(f[i-2][j-1]*C_{i-1}^1*C_j^1\)
     
    由于可以存在空的点,所以算出来的\(f[H][W]\)并不是最终的答案。最后统计答案时,总答案为:
    \(\sum_{i=1}^H\sum_{j=1}^W f[i][j]*C_H^i*C_W^j\)

KONO代码哒!

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll c[3010][3010];
ll f[3010][3010];
ll n, m;
ll add(ll x, ll y) { return ((x % mod) + (y % mod)) % mod; }
ll ads(ll x, ll y) { return (x % mod) * (y % mod) % mod; }
int main() {
    ll i, j;
    scanf("%lld%lld", &n, &m);
    c[1][0] = c[1][1] = 1;
    for (i = 2; i <= max(n, m); i++) {
        c[i][0] = 1;
        for (j = 1; j <= i; j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
    f[0][0] = 1;
    for (i = 1; i <= n; i++) {
        for (j = 1; j <= m; j++) {
            f[i][j] = add(f[i][j], ads(4LL, ads(f[i - 1][j - 1], j)));
            if (j >= 2)
                f[i][j] = add(f[i][j], ads(f[i - 1][j - 2], c[j][2]));
            if (i >= 2)
                f[i][j] = add(f[i][j], ads(f[i - 2][j - 1], ads(i - 1, j)));
        }
    }
    ll ans = 0;
    for (i = 1; i <= n; i++) {
        for (j = 1; j <= m; j++) {
            ans = add(ans, ads(f[i][j], ads(c[n][i], c[m][j])));
        }
    }
    printf("%lld\n", ans);
}

为了省代码长度把\(+\),\(*\)操作打成了函数(其实就是懒)
全OJ跑的最慢的之一

posted @ 2019-11-07 20:46  国土战略局特工  阅读(135)  评论(0)    收藏  举报