noip模拟24
A.matrix
简单的状压搜索,记忆化优化..
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll int
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x);
#define Copy(x,y) memset(y,x,sizeof x);
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48); puts("");
}
} using namespace BSS;
ll n,m;
ll g[15][15],c[15][15];
ll f[15][(1<<10)+50][(1<<10)+50];
ll Work(ll now,ll dad,ll lst) // 当前是第 now 层,父亲的状态为 dad,父亲选的为 lst
{
if(now==n+1)
{
for(re i=1;i<=m;i++)
{
if(((dad>>(i-1))&1)==0) return 1e9;
}
return 0;
}
if(f[now][dad][lst]) return f[now][dad][lst];
ll nxt=0,sta=0,cost;
for(re i=1;i<=m;i++)
{
if((lst>>(i-1))&1) sta|=(1<<(i-1));
if(g[now][i]) sta|=(1<<(i-1));
if(((dad>>(i-1))&1)==0) nxt|=(1<<(i-1));
}
f[now][dad][lst]=1e9;
ll temp;
for(re i=0;i<=(1<<m)-1;i++)
{
cost=0; temp=sta;
if((i|nxt)!=i) continue;
for(re j=1;j<=m;j++)
{
if((i>>j)&1) temp|=(1<<(j-1));
if((i>>(j-1))&1) temp|=(1<<(j-1));
if(j>=2) if((i>>(j-2))&1) temp|=(1<<(j-1));
if((i>>(j-1))&1) cost+=c[now][j];
if(cost>=f[now][dad][lst]) break;
}
if(cost>=f[now][dad][lst]) continue;
f[now][dad][lst]=min(f[now][dad][lst],cost+Work(now+1,temp,i));
}
return f[now][dad][lst];
}
signed main()
{
n=read(); m=read();
char s[20];
for(re i=1;i<=n;i++)
{
scanf("%s",s+1);
for(re j=1;j<=m;j++)
{
g[i][j]=s[j]-'0';
}
}
for(re i=1;i<=n;i++)
{
for(re j=1;j<=m;j++)
{
c[i][j]=read();
}
}
ll sta,cost,ans=1e9;
for(re i=0;i<=(1<<m)-1;i++)
{
cost=0; sta=0;
for(re j=1;j<=m;j++)
{
if(g[1][j]) sta|=(1<<(j-1));
if((i>>j)&1) sta|=(1<<(j-1));
if((i>>(j-1))&1) sta|=(1<<(j-1));
if(j>=2) if((i>>(j-2))&1) sta|=(1<<(j-1));
if((i>>(j-1))&1) cost+=c[1][j];
if(cost>=ans) break;
}
if(cost>=ans) continue;
ans=min(ans,Work(2,sta,i)+cost);
}
write(ans);
return 0;
}
B.block
第一问和第二问关系不大..
第一问:
考虑插入的方案数即可..
第二问:
考虑线段树维护.
首先保证输出为合法答案,所以当\(key\)存在\(1\),优先考虑其的安置;\(key\)中不含\(1\)时,考虑字典序最小.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x);
#define Copy(x,y) memset(y,x,sizeof x);
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48); puts("");
}
} using namespace BSS;
const ll N=6e5+50;
const ll mod=1e9+7;
ll m,n,ans=1,cnt,tt;
ll pos[N],lsh[N];
struct I { ll val,key; } p[N];
struct II { ll key,posi; } ;
struct III { ll l,r,lazy; II k0,k2; } tr[N*8];
bool comp1(I i,I j) { return i.val==j.val ? i.key<j.key : i.val>j.val; }
bool comp2(I i,I j) { return i.val==j.val ? i.key<j.key : i.val<j.val; }
inline void Work_One()
{
sort(p+1,p+1+n,comp1);
ll lst=0;
for(ll i=1;i<=n;i++)
{
if(p[i].val!=p[i-1].val)
{
ans=(ans*min(i,p[i].key))%mod;
lst=1;
}
else
{
ans=(ans*min(i,p[i].key+lst))%mod;
lst++;
}
}
write(ans); return ;
}
void pushup(ll x)
{
if(tr[x<<1].k0.key<=tr[x<<1|1].k0.key) tr[x].k0=tr[x<<1].k0;
else tr[x].k0=tr[x<<1|1].k0;
if(tr[x<<1].k2.key<=tr[x<<1|1].k2.key) tr[x].k2=tr[x<<1].k2;
else tr[x].k2=tr[x<<1|1].k2;
// if(tr[x].k0.key==1) cout<<tr[x].k0.key<<" "<<tr[x].l<<" "<<tr[x].r<<" "<<tr[x<<1].k0.key<<" "<<tr[x<<1|1].k0.key<<endl;
return ;
}
void spread(ll x)
{
if(tr[x].lazy!=0)
{
tr[x<<1].lazy+=tr[x].lazy;
tr[x<<1|1].lazy+=tr[x].lazy;
tr[x<<1].k2.key+=tr[x].lazy;
tr[x<<1|1].k2.key+=tr[x].lazy;
tr[x].lazy=0;
}
return ;
}
void update(ll x,ll ql,ll qr,ll val)
{
if(ql>qr or qr<=0) return ;
if(tr[x].l>=ql and tr[x].r<=qr)
{
tr[x].k2.key+=val;
tr[x].lazy+=val;
if(val==1e10) tr[x].k0.key=tr[x].k2.key=1e10;
return ;
}
spread(x);
ll mid=(tr[x].l+tr[x].r)>>1;
if(ql<=mid) update(x<<1,ql,qr,val);
if(qr>=mid+1) update(x<<1|1,ql,qr,val);
pushup(x); return ;
}
void build(ll x,ll l,ll r)
{
tr[x].l=l,tr[x].r=r;
if(tr[x].l==tr[x].r)
{
tr[x].k0.key=tr[x].k2.key=p[l].key;
tr[x].k0.posi=tr[x].k2.posi=l;
return ;
}
ll mid=(l+r)>>1;
build(x<<1,l,mid); build(x<<1|1,mid+1,r);
pushup(x);
}
II query(ll x,ll ql,ll qr)
{
if(ql>qr) return (II){0,0};
if(tr[x].l>=ql and tr[x].r<=qr)
{
return tr[x].k0;
}
ll mid=(tr[x].l+tr[x].r)>>1;
if(ql<=mid and qr>=mid+1)
{
II temp1=query(x<<1,ql,qr);
II temp2=query(x<<1|1,ql,qr);
if(temp1.key<=temp2.key) return temp1;
else return temp2;
}
else if(ql<=mid)
{
return query(x<<1,ql,qr);
}
else if(qr>=mid+1)
{
return query(x<<1|1,ql,qr);
}
}
inline void Work_Two()
{
sort(p+1,p+1+n,comp2);
for(re i=1;i<=n;i++) lsh[i]=p[i].val;
sort(lsh+1,lsh+1+n);
cnt=unique(lsh+1,lsh+1+n)-lsh-1;
for(re i=1;i<=n;i++) p[i].val=lb(lsh+1,lsh+1+cnt,p[i].val)-lsh;
for(re i=1;i<=n;i++) if(p[i].val!=p[i-1].val) pos[p[i].val]=i;
build(1,1,n);
for(re i=1;i<=n;i++)
{
if(tr[1].k2.key==1)
{
II temp=query(1,1,tr[1].k2.posi);
printf("%lld %lld\n",temp.key,lsh[p[temp.posi].val]);
update(1,temp.posi,temp.posi,1e10);
update(1,1,pos[p[temp.posi].val]-1,-1);
}
else
{
ll temp=p[tr[1].k0.posi].val;
printf("%lld %lld\n",tr[1].k0.key,lsh[temp]);
update(1,tr[1].k0.posi,tr[1].k0.posi,1e10);
update(1,1,pos[temp]-1,-1);
}
}
return ;
}
signed main()
{
// File(0.in,out);
n=read();
for(re i=1;i<=n;i++) p[i].key=read(),p[i].val=read();
Work_One(); Work_Two();
return 0;
}
C.graph
如果一个点能位于 \(1\) ~ \(n\) 的最短路上,那么 \(dis_{1,i}+dis_{i,n}==dis_{1,n}\).
所以考虑如何找到一个 \(x\) ,能够满足上述条件.
暴力的思想就是枚举 \(x\) 的所有值,考虑如何优化.
设 \(dis_{i,j}\) 为到达点 \(i\),经过了 \(j\) 条 \(x\) 边的最短距离.
发现 \(x\) 的值域位于某一个区间内时,效果是等价的.
由于 \(x\) 的值越大,越不可能经过 \(x\) 边,所以可以对于每一个 \(i\) 计算出以它作为最小值的 \(x\) 取值区间.
在这个取值区间中随便取一个值赋给 \(x\),然后跑两个最短路.
对于每个节点判断是否有可能在最短路上即可.
这样就可以统计所有点,简单反证就可以证明其合理性.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define ull unsigned ll
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
inline ll read()
{
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=1021,M=2021;
const ll inf=1e12;
int ans[N];
ll m,n,ts,sum;
ll head[N],v[N];
ll d[N][2],dis[N][M],vis[N][M];
struct I { ll u,v,w,nxt; } e[M<<1];
struct II {
ll u,xs,w;
II(){} II(ll i,ll j,ll k){ u=i,xs=j,w=k; }
bool operator <(const II &x)const{
return x.w<w;
}
};
struct III {
ll u,w;
III(){} III(ll i,ll j){ u=i,w=j; }
bool operator <(const III &x)const{
return x.w<w;
}
};
priority_queue<II> que; priority_queue<III> Q;
inline void add(ll u,ll v,ll w){
e[++ts].u=u,e[ts].v=v,e[ts].w=w,e[ts].nxt=head[u],
head[u]=ts;
}
inline void Dijk(){
Fill(dis,0x3f); while(que.size()) que.pop();
dis[1][0]=0,que.push(II(1,0,0)); ll u,xs;
while(que.size()){
u=que.top().u,xs=que.top().xs,que.pop();
if(vis[u][xs]) continue; vis[u][xs]=1;
for(re i=head[u];i;i=e[i].nxt){
if(e[i].w==-1){
if(xs<sum and dis[e[i].v][xs+1]>dis[u][xs]){
dis[e[i].v][xs+1]=dis[u][xs];
que.push(II(e[i].v,xs+1,dis[e[i].v][xs+1]));
}
}
else{
if(dis[e[i].v][xs]>dis[u][xs]+e[i].w){
dis[e[i].v][xs]=dis[u][xs]+e[i].w;
que.push(II(e[i].v,xs,dis[e[i].v][xs]));
}
}
}
}
}
inline void dijk(ll z,ll x){
Fill(v,0); while(Q.size()) Q.pop();
if(z) d[1][1]=0,Q.push(III(1,0));
else d[n][0]=0,Q.push(III(n,0));
ll u;
while(Q.size()){
u=Q.top().u,Q.pop();
if(v[u]) continue; v[u]=1;
for(re i=head[u];i;i=e[i].nxt){
if(e[i].w==-1){
if(d[e[i].v][z]>d[u][z]+x){
d[e[i].v][z]=d[u][z]+x;
Q.push(III(e[i].v,d[e[i].v][z]));
}
}
else{
if(d[e[i].v][z]>d[u][z]+e[i].w){
d[e[i].v][z]=d[u][z]+e[i].w;
Q.push(III(e[i].v,d[e[i].v][z]));
}
}
}
}
}
signed main(){
n=read(),m=read(); ll u,v,w,l,r;
for(re i=1;i<=m;i++)
u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w),sum+=(w==-1);
Dijk();
// for(re i=0;i<=sum;i++){
// for(re j=1;j<=n;j++)
// cout<<dis[j][i]<<' ';
// cout<<endl;
// }
for(re i=0;i<=sum;i++){
l=0,r=inf;
for(re j=0;j<i;j++) r=min(r,(dis[n][j]-dis[n][i])/(i-j));
for(re j=i+1;j<=sum;j++) l=max(l,(ll)ceil((lf)(dis[n][i]-dis[n][j])/(j-i)));
if(l>r) continue; Fill(d,0x3f),dijk(1,l),dijk(0,l);
// cout<<"L:"<<l<<" R:"<<r<<endl;
// for(re j=1;j<=n;j++) cout<<d[j][0]<<" "<<d[j][1]<<endl;
// cout<<endl;
for(re j=1;j<=n;j++) if(d[j][1]+d[j][0]==d[n][1]) ans[j]=1;
}
for(re i=1;i<=n;i++) printf("%d",ans[i]);
exit(0);
}