您的位置:首页 > 其它

cqoi2016

2016-05-23 00:07 288 查看

cqoi2016

不同的最小割

做法同zjoi2011最小割,题解略。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define inf 1050000000
#define N 855
#define M 17005
using namespace std;
int n,m,S,T,tot,po
,lx
,rx
,ans

;
int k=1,la
,ff[M],q
,dep
,flag
,out[N*N];
struct node{int a,b,c;}map[M];

void add(int a,int b,int c)
{
map[++k]=(node){a,b,c};ff[k]=la[a];la[a]=k;
map[++k]=(node){b,a,c};ff[k]=la;la[b]=k;
}

int dfs(int x,int flow)
{
if(x==T)return flow;
int res=0,tmp;
for(int a=la[x];a&&flow>0;a=ff[a])
if(dep[map[a].b]==dep[x]+1&&map[a].c)
{
tmp=dfs(map[a].b,min(flow,map[a].c));
map[a].c-=tmp;map[a^1].c+=tmp;res+=tmp;flow-=tmp;
}
if(res==0)dep[x]=-1;
return res;
}

bool bfs()
{
memset(dep,0,sizeof(dep));
int l=1,r=2;q[1]=S;dep[S]=1;
while(l<r)
{
int x=q[l];l++;
for(int a=la[x];a;a=ff[a])
if(!dep[map[a].b]&&map[a].c)
q[r]=map[a].b,dep[q[r]]=dep[x]+1,r++;
}
return dep[T];
}

void dfs(int x)
{
flag[x]=1;
for(int a=la[x];a;a=ff[a])
if(map[a].c&&!flag[map[a].b])dfs(map[a].b);
}

void solve(int l,int r)
{
if(l==r)return;
int res=0;S=po[l];T=po[r];
for(int i=2;i<=k;i+=2)
map[i].c=map[i^1].c=(map[i].c+map[i^1].c>>1);
while(bfs())res+=dfs(S,inf);
memset(flag,0,sizeof(flag));dfs(S);
for(int i=1;i<=n;i++)if(flag[i])
for(int j=1;j<=n;j++)if(!flag[j])
ans[i][j]=ans[j][i]=min(ans[i][j],res);
int l1=0,l2=0;
for(int i=l;i<=r;i++)
{
if(flag[po[i]])lx[++l1]=po[i];
else rx[++l2]=po[i];
}
for(int i=l,j=1;j<=l1;i++,j++)po[i]=lx[j];
for(int i=l+l1,j=1;j<=l2;i++,j++)po[i]=rx[j];
solve(l,l+l1-1);solve(l+l1,r);
}

int main()
{
int a,b,c,x,res;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)po[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&a,&b,&c),add(a,b,c);
memset(ans,127,sizeof(ans));
solve(1,n);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)out[++tot]=ans[i][j];
sort(out+1,out+tot+1);
printf("%d\n",unique(out+1,out+tot+1)-out-1);
return 0;
}


[b]K远点对


裸的kd树维护最远点对。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#define inf 2100000000
#define ll long long
#define N 100010
using namespace std;
int n,rt,k,D,cnt;
struct info{
int c[2];
bool operator<(const info &x)const{
return c[D]<x.c[D]||(c[D]==x.c[D]&&c[D^1]<x.c[D^1]);
}
}s
;
struct node{int lc,rc,minx,maxx,miny,maxy,x,y;}t
;
priority_queue<ll>q;

class Kevin_Durant_Tree
{
void update(int x)
{
int lc=t[x].lc,rc=t[x].rc;
t[x].minx=min(t[x].x,min(t[lc].minx,t[rc].minx));
t[x].miny=min(t[x].y,min(t[lc].miny,t[rc].miny));
t[x].maxx=max(t[x].x,max(t[lc].maxx,t[rc].maxx));
t[x].maxy=max(t[x].y,max(t[lc].maxy,t[rc].maxy));
}
ll pf(int x){return (ll)x*x;}
ll get(int x1,int y1,int x2,int y2)
{
return pf(x1-x2)+pf(y1-y2);
}
ll cal(int x,int X,int Y)
{
if(!x)return 0;
ll res=0;
res=max(res,get(t[x].minx,t[x].miny,X,Y));
res=max(res,get(t[x].minx,t[x].maxy,X,Y));
res=max(res,get(t[x].maxx,t[x].miny,X,Y));
res=max(res,get(t[x].maxx,t[x].maxy,X,Y));
return res;
}
public:
void build(int &x,int l,int r,int inv)
{
if(l>r)return;x=++cnt;
int mid=l+r>>1;
D=inv;nth_element(s+l,s+mid,s+r+1);
t[x].minx=t[x].maxx=t[x].x=s[mid].c[0];
t[x].miny=t[x].maxy=t[x].y=s[mid].c[1];
build(t[x].lc,l,mid-1,inv^1);
build(t[x].rc,mid+1,r,inv^1);
update(x);
}
void qry(int x,int X,int Y)
{
if(!x)return;
int lc=t[x].lc,rc=t[x].rc;
ll ls=cal(lc,X,Y),rs=cal(rc,X,Y);
ll tmp=get(t[x].x,t[x].y,X,Y);
if(tmp>-q.top())q.pop(),q.push(-tmp);
if(ls>rs)
{
if(ls>-q.top())qry(lc,X,Y);
if(rs>-q.top())qry(rc,X,Y);
}
else
{
if(rs>-q.top())qry(rc,X,Y);
if(ls>-q.top())qry(lc,X,Y);
}
}
void clear()
{
t[0].minx=t[0].miny=inf;
t[0].maxx=t[0].maxy=0;
}
}T;

int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d%d",&s[i].c[0],&s[i].c[1]);
T.clear();T.build(rt,1,n,0);
for(int i=1;i<=2*k;i++)q.push(0);
for(int i=1;i<=n;i++)
T.qry(rt,s[i].c[0],s[i].c[1]);
printf("%lld\n",-q.top());
return 0;
}


手机号码

裸的数位dp,f[x][A][C][D][E][F]分别表示前x位,上一位为A,连续B个相同,是否满足连续超过3个相同,是否有4,是否有8,是否等于上界。

写成记忆化搜索代码会好写很多。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define ll long long
#define N 13
using namespace std;
int flag

[4][2][2][2][2],f

[4][2][2][2][2],p
;ll l,r,s
;

int dfs(int x,int A,int B,int C,int D,int E,ll num)
{
if((num>s[x+1])||(D&&E)||(x<0&&!C))return 0;
if(x<0)return 1;
int F=(num==s[x+1]);
if(flag[x][A][B][C][D][E][F])return f[x][A][B][C][D][E][F];
flag[x][A][B][C][D][E][F]=1;ll tmp=0;
for(int i=0;i<=9;i++)
{
if(i==A)tmp+=dfs(x-1,i,min(B+1,3),C|(B>=2),D|(i==4),E|(i==8),num*10+i);
else tmp+=dfs(x-1,i,1,C,D|(i==4),E|(i==8),num*10+i);
}
return f[x][A][B][C][D][E][F]=tmp;
}

ll work(ll x)
{
ll res=0,t=x;
memset(f,0,sizeof(f));
memset(flag,0,sizeof(flag));
for(int i=0;i<=10;i++)p[i]=t%10,t/=10;
for(int i=10;i>=0;i--)s[i]=s[i+1]*10+p[i];
for(int i=1;i<=9;i++)
res+=dfs(9,i,1,0,i==4,i==8,i);
return res;
}

int main()
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",work(r)-work(l-1));
return 0;
}


[b]密钥破解


模拟+泼辣肉。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define ll unsigned long long
using namespace std;
ll e,N,c,n,d,p,q,r,x,y,num;

ll add(ll a,ll b,ll mod)
{return (a+=b)>=mod?a-mod:a;}

ll mul(ll a,ll b,ll n)
{
ll res=0;a%=n;b%=n;
while(b)
{
if(b&1)res=add(res,a,n);
a=(a<<1)%n;b=b>>1;
}
return res;
}

ll Pow(ll a,ll b,ll mod)
{
ll res=1;
while(b)
{
if(b&1)res=mul(res,a,mod);
a=mul(a,a,mod);b>>=1;
}
return res;
}

ll gcd(ll a,ll b)
{
if(!b)return a;
return gcd(b,a%b);
}

void exgcd(ll a,ll b)
{
if(b==0){x=1;y=0;return;}
exgcd(b,a%b);ll t=x;x=y;y=t-a/b*y;
}

ll Abs(ll x){return x>0?x:-x;}

ll Pollard_rho(ll n,ll c)
{
ll i=1,k=2,x,y,d,p;
x=rand()%(n-1)+1;y=x;
while(1)
{
i++;x=add(mul(x,x,n),c,n);
if(y==x)return n;
p=Abs(x-y);d=gcd(p,n);
if(d!=1&&d!=n)return d;
if(i==k)y=x,k+=k;
}
}

int main()
{
srand(666072);
scanf("%lld%lld%lld",&e,&N,&c);
if(N<=1000000)num=072;
else num=666;
p=Pollard_rho(N,num);
q=N/p;r=(p-1)*(q-1);
exgcd(e,r);d=(x+r)%r;
n=Pow(c,d,N);
printf("%lld% lld\n",d,n);
return 0;
}


路由表

语文题。建chuai树,每次查询等价于维护一段时间递增序列。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define N 1000010
using namespace std;
int n,cnt,tot,ch
[2],pos
,q
,str[50];
char s[20];

class chuai
{
public:
int cal(int top,int l)
{
int res=0;
for(int i=1;i<=top;i++)res+=(q[i]>=l);
return res;
}
void insert(int *s,int len,int ti)
{
int x=0;
for(int i=1;i<=len;i++)
{
if(!ch[x][s[i]])ch[x][s[i]]=++cnt;
x=ch[x][s[i]];
}
pos[x]=ti;
}
int qry(int *s,int l,int r,int len)
{
int x=0,top=0;
for(int i=1;i<=len;i++)
{
x=ch[x][s[i]];
if(!x)return cal(top,l);
if(pos[x]&&pos[x]<=r)
{
while(q[top]>pos[x]&&top)top--;
q[++top]=pos[x];
}
}
return cal(top,l);
}
}T;

int main()
{
char ch,cyc,wbs,lxe,yp;
int l,r,num,len,A,B,C,D;
scanf("%d",&n);
while(n--)
{
scanf(" %c%d %c%d %c%d %c%d",&ch,&A,&wbs,&B,&cyc,&C,&lxe,&D);
if(ch=='A')
{
scanf(" %c%d",&yp,&len);
num=A;num=num*256+B;
num=num*256+C;num=num*256+D;
for(int i=1,j=31;i<=len;i++,j--)str[i]=((num>>j)&1);
T.insert(str,len,++tot);
}
else
{
scanf("%d%d",&l,&r);
len=32;num=A;num=num*256+B;
num=num*256+C;num=num*256+D;
for(int i=1,j=31;i<=len;i++,j--)str[i]=((num>>j)&1);
printf("%d\n",T.qry(str,l,r,len));
}
}
return 0;
}


伪光滑数

终于有一道有点意思的题目。

考虑只要求最大,建立dp,f[i][j]表示前i小额质数选j个的最大值。

维护一下前缀和即可。

f[i][j]=g[i-1][j-k]*num;

g[i][j]=g[i-1][j]+f[i][j];

要求K大,就把每个状态改成一个堆,再把所有状态套进一个大堆。

跑K次,每次取出一个节点换次大。

乘法等价于在堆上打标机,加法等价于合并两个堆。

拿可持久化可并队维护即可。

感觉这种堆套堆得方法还是很经典的。

cyc大爷的做法,二分答案暴搜,直接A了(%%%)。

lxe大爷的做法,对于每个状态维护每个质数使用的个数,然后对于每个状态只对最后两个数字进行转移。也A了(%%%)。lxe大爷似乎用奇怪的办法拆解了我的这个dp,然后码量少了不少。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#define ll long long
#define N 18000000
#define MAX 127
using namespace std;
int k,D,cnt=1,f[MAX][65],g[MAX][65];
int tot,check[MAX],prime[MAX];ll n;
struct node{int lc,rc,dis;ll num,tag;}t
;
struct info{
int x,y;ll num;
bool operator<(const info &p)
const{return num<p.num;}
};
priority_queue<info>q;

class heap
{
void pushdown(int x)
{
if(t[x].tag==1)return;
int lc=t[x].lc,rc=t[x].rc;
if(lc)
{
t[++cnt]=t[lc];t[x].lc=cnt;
t[cnt].num*=t[x].tag;
t[cnt].tag*=t[x].tag;
}
if(rc)
{
t[++cnt]=t[rc];t[x].rc=cnt;
t[cnt].num*=t[x].tag;
t[cnt].tag*=t[x].tag;
}
t[x].tag=1;
}
public:
int merge(int a,int b)
{
if(!a)return b;if(!b)return a;
if(t[a].num<t[b].num)swap(a,b);
int x=++cnt;t[x]=t[a];pushdown(x);
t[x].rc=merge(t[x].rc,b);
if(t[t[x].lc].dis<t[t[x].rc].dis)
swap(t[x].lc,t[x].rc);
t[x].dis=t[t[x].rc].dis+1;
return x;
}
int mul(int x,ll y)
{
t[++cnt]=t[x];t[cnt].tag*=y;t[cnt].num*=y;
return cnt;
}
int add(int a,int b){return merge(a,b);}
int erase(int x)
{
pushdown(x);
return merge(t[x].lc,t[x].rc);
}
}T;

int main()
{
scanf("%lld%d",&n,&k);D=log2(n)+1;
for(int i=2;i<=MAX;i++)
{
if(check[i])continue;prime[++tot]=i;
for(int j=i;j<=MAX;j+=i)check[j]=1;
}
for(int i=0;i<=D;i++)f[0][i]=g[0][i]=1;
t[1].num=t[1].tag=t[1].dis=1;
for(int i=1;i<=tot;i++)
{
ll ss=1;g[i][0]=g[i-1][0];
for(int j=1;;j++)
{
ss*=prime[i];
if(ss<=0||ss>n)break;
ll num=1;
for(int k=1;k<=j;k++)
{
num*=prime[i];
f[i][j]=T.add(f[i][j],T.mul(g[i-1][j-k],num));
}
q.push((info){i,j,t[f[i][j]].num});
g[i][j]=T.add(g[i-1][j],f[i][j]);
}
}
ll pre=0;
for(int i=1;i<k;i++)
{
info x=q.top();q.pop();
if(x.num==pre)i--;pre=x.num;
f[x.x][x.y]=T.erase(f[x.x][x.y]);
q.push((info){x.x,x.y,t[f[x.x][x.y]].num});
}
printf("%lld\n",q.top().num);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: