冲刺清北营 4
今天成人礼。于是打算写点无营养鲜花。
口胡场都能被打自闭,真有你的。
一花 二乃 三玖 四叶 五月 六小.jpg
那你说的对。
猴戏世家
P4737。
场上脑抽,想到了后一半,没想到前一半。死于一直想从下到上扫描线无果,然后开始想怎么在线做。
从上到下扫描线,然后开个 set 维护栅栏。扫到一个点:
- 猴:找到右边第一个栅栏,就是它的。
- 栅栏:插入 set。
这样我们找到了每个栅栏包含哪些点。然后对于一个栅栏,它完全包含的在它后边加入的栅栏也是算作它的答案里的。这玩意显然成一个树形结构。于是并查集倒着扫一遍询问就行了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
set<pair<int,int> >s;
int n,m,ans[300010],fa[300010],size[300010],f[300010];
struct node{
int x,y,od;
bool operator<(const node&s)const{
return y==s.y?od>s.od:y>s.y;
}
}p[600010];
int find(int x){
return f[x]==x?f[x]:f[x]=find(f[x]);
}
void merge(int x,int y){
x=find(x);y=find(y);
if(x==y)return;
f[y]=x;size[x]+=size[y];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y);
scanf("%d",&m);
for(int i=1;i<=m;i++)scanf("%d%d",&p[n+i].x,&p[n+i].y),p[n+i].od=i,f[i]=i;
sort(p+1,p+n+m+1);
for(int i=1;i<=n+m;i++){
if(p[i].od){
s.insert(make_pair(p[i].x,p[i].od));
set<pair<int,int> >::iterator it=s.find(make_pair(p[i].x,p[i].od));
if(++it!=s.end())fa[p[i].od]=it->second;
while(1){
it=s.find(make_pair(p[i].x,p[i].od));
if(it==s.begin())break;
--it;
if(it->second>p[i].od)s.erase(it);
else break;
}
}
else{
set<pair<int,int> >::iterator it=s.lower_bound(make_pair(p[i].x,0));
if(it!=s.end())size[it->second]++;
}
}
for(int i=m;i>=1;i--){
ans[i]=size[find(i)];
if(fa[i])merge(fa[i],i);
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
零糖麦片
CF468E。
啊这。
首先这玩意叫积和式不叫集合式。然后算这玩意没多项式复杂度解法。
于是考虑一个状压:先所有 \(w-1\)。然后设修改过的行的集合为 \(S\),每次枚举 \(S\) 的合法的子集代表选中了这些 \(w\),如果选了 \(t\) 个那么贡献乘个 \((n-t)!\)。正确性显然,复杂度 \(O(k^22^k)\) 的,显然过不去。
考虑优化,发现如果一行只有一个元素可能被选,那么不用把它压进状态里,于是只需要考虑修改元素个数 \(\ge 2\) 的行,复杂度变成 \(O(k^22^{\frac k2})\)。
看起来极限情况还是过不去。那么加个玄学优化:扫完了所有状态的行显然可以去掉,那么我们先扫元素个数少的行。然后跑的飞快。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <unordered_map>
#define int long long
using namespace std;
const int mod=1000000007;
int n,k,ans,jc[100010],lsh1[60],lsh2[60],x[60],y[60],w[60],a[60][60],cnt1[60],cnt2[60];
unordered_map<int,int>dp[2][60];
signed main(){
memset(a,-1,sizeof(a));
scanf("%lld%lld",&n,&k);jc[0]=1;
for(int i=1;i<=n;i++)jc[i]=1ll*jc[i-1]*i%mod;
for(int i=1;i<=k;i++){
scanf("%lld%lld%lld",&x[i],&y[i],&w[i]);w[i]=(w[i]+mod-1)%mod;
lsh1[++lsh1[0]]=x[i];lsh2[++lsh2[0]]=y[i];
}
sort(lsh1+1,lsh1+lsh1[0]+1);sort(lsh2+1,lsh2+lsh2[0]+1);
lsh1[0]=unique(lsh1+1,lsh1+lsh1[0]+1)-lsh1-1;
lsh2[0]=unique(lsh2+1,lsh2+lsh2[0]+1)-lsh2-1;
for(int i=1;i<=k;i++){
x[i]=lower_bound(lsh1+1,lsh1+lsh1[0]+1,x[i])-lsh1;
y[i]=lower_bound(lsh2+1,lsh2+lsh2[0]+1,y[i])-lsh2;
a[x[i]][y[i]]=w[i];
cnt1[x[i]]++;cnt2[y[i]]++;
}
dp[0][0][0]=1;int cur=0;
while(1){
int od=-1;
for(int i=1;i<=lsh2[0];i++){
if(cnt2[i]&&(od==-1||cnt2[od]>cnt2[i]))od=i;
}
if(od==-1)break;
for(int i=1;i<=lsh1[0];i++){
if(a[i][od]!=-1&&cnt1[i]){
cnt1[i]=0;
int s=(1ll<<lsh2[0])-1<<1,t=0;
vector<int>ret;
for(int j=1;j<=lsh2[0];j++){
if(a[i][j]!=-1){
ret.push_back(j);
cnt2[j]--;t|=1ll<<j;
if(!cnt2[j])s^=1ll<<j;
}
}
cur^=1;
for(int j=0;j<=k;j++)dp[cur][j].clear();
for(int z=0;z<=k;z++){
for(pair<int,int>p:dp[cur^1][z]){
dp[cur][z][p.first&s]=(dp[cur][z][p.first&s]+p.second)%mod;
for(int x:ret){
if(!((p.first>>x)&1)){
dp[cur][z+1][(p.first|(1ll<<x))&s]=(dp[cur][z+1][(p.first|(1ll<<x))&s]+1ll*p.second*a[i][x])%mod;
}
}
}
}
}
}
}
for(int i=0;i<=k;i++)for(pair<int,int>p:dp[cur][i])ans=(ans+1ll*p.second*jc[n-i])%mod;
printf("%lld\n",ans);
return 0;
}
文体双花
线段树扫描线 + 单调栈。签到题,具体参考 pudding monsters。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <bitset>
#include <queue>
#define int long long
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int mod=1000000007;
int n,p[100010],dp[100010];
struct node{
int min,cnt;
node operator+(const int &s)const{
return{min+s,cnt};
}
node friend operator+(node s,node t){
node ret={};
ret.min=std::min(s.min,t.min);
if(ret.min==s.min)ret.cnt+=s.cnt;
if(ret.min==t.min)ret.cnt+=t.cnt;
ret.cnt%=mod;
return ret;
}
};
struct Seg{
int lz;
node val;
}tree[400010];
void pushup(int rt){
tree[rt].val=tree[lson].val+tree[rson].val;
}
void pushtag(int rt,int val){
tree[rt].val=tree[rt].val+val;tree[rt].lz+=val;
}
void pushdown(int rt){
if(tree[rt].lz){
pushtag(lson,tree[rt].lz);
pushtag(rson,tree[rt].lz);
tree[rt].lz=0;
}
}
void update(int rt,int L,int R,int l,int r,int val){
if(l<=L&&R<=r){
pushtag(rt,val);return;
}
pushdown(rt);
int mid=(L+R)>>1;
if(l<=mid)update(lson,L,mid,l,r,val);
if(mid<r)update(rson,mid+1,R,l,r,val);
pushup(rt);
}
void updatecnt(int rt,int L,int R,int pos,int val){
if(L==R){
tree[rt].val.cnt=val;return;
}
pushdown(rt);
int mid=(L+R)>>1;
if(pos<=mid)updatecnt(lson,L,mid,pos,val);
else updatecnt(rson,mid+1,R,pos,val);
pushup(rt);
}
node query(int rt,int L,int R,int l,int r){
if(l<=L&&R<=r)return tree[rt].val;
int mid=(L+R)>>1;
node val={0x3f3f3f3f,0};
if(l<=mid)val=val+query(lson,L,mid,l,r);
if(mid<r)val=val+query(rson,mid+1,R,l,r);
return val;
}
int stk1[100010],stk2[100010],top1,top2;
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&p[i]);
dp[0]=1;
for(int i=1;i<=n;i++){
updatecnt(1,1,n,i,dp[i-1]);
while(top1&&p[i]<=p[stk1[top1]]){
update(1,1,n,stk1[top1-1]+1,stk1[top1],p[stk1[top1]]);
top1--;
}
while(top2&&p[i]>=p[stk2[top2]]){
update(1,1,n,stk2[top2-1]+1,stk2[top2],-p[stk2[top2]]);
top2--;
}
update(1,1,n,stk1[top1]+1,i,-p[i]);
update(1,1,n,stk2[top2]+1,i,p[i]);
stk1[++top1]=stk2[++top2]=i;
update(1,1,n,i,i,i);
dp[i]=query(1,1,n,1,i).cnt;
}
printf("%lld\n",dp[n]);
return 0;
}
快踩