SDOI2016 Round 1解題報告
題目大意:
已知
題解:
可以按照數位dp的思想來做,每次考慮在當前這個數的二進位制位和
但是數位dp畢竟難寫難調,我們可以繼續考慮,有一棵
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 70
#define LL long long
LL n,m,K,P,ans,mi[N];
inline int in(){
int x=0; char ch=getchar(); bool f=1;
while (ch<'0'||ch>'9'){
if (ch=='-') f=0;
ch=getchar();
}while (ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
if (!f) x=-x; return x;
}
inline LL Lin(){
LL x=0; char ch=getchar(); bool f=1;
while (ch<'0'||ch>'9'){
if (ch=='-' ) f=0;
ch=getchar();
}while (ch>='0'&&ch<='9')
x=x*10ll+(LL)(ch-'0'),ch=getchar();
if (!f) x=-x; return x;
}
inline LL calc(LL x,LL y){
LL s=(((x+y)%(P*2ll))*((y-x+1)%(P*2ll)))%(P*2ll);
s/=2ll,s%=P; return s;
}
inline LL work(LL x,LL y,int xx,int yy){
LL s=0,z; if (xx<yy) swap(x,y),swap(xx,yy);
x^=(x&(mi[xx]-1)),y^=(y&(mi[xx]-1)),z=x^y;
if (z>K) s=calc(z-K,z+mi[xx]-K-1);
else if ((z+mi[xx])>K) s=calc(0,z+mi[xx]-K-1);
s=(s*(mi[yy]%P))%P; return s;
}
int main(){
int T=in(),i,j,tt; LL x,y;
mi[0]=1ll;
for (i=1; i<=62; i++) mi[i]=mi[i-1]<<1;
for (tt=1; tt<=T; tt++){
n=Lin(),m=Lin(),K=Lin();
P=Lin(),x=0ll,ans=0ll;
for (i=62; i>=0; i--){
if (n&mi[i]){
y=0ll;
for (j=62; j>=0; j--){
if (m&mi[j]){
ans=(ans+work(x,y,i,j))%P,y|=mi[j];
}
}x|=mi[i];
}
}printf("%I64d\n",ans);
}return 0;
}
題目大意:
給出n個數,對於兩個數
題解:
最大費用最大流。題目中給出的是一個二分圖,對其建網路流圖:
每個奇數個質因子的數
每個偶數個質因子的數
然後跑最大費用流,直到某次增廣後總費用為負,計算一下最後跑的流量即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 610
#define M 600010
#define P 2000000
#define inf 1000000000
#define limit -100000000000000ll
#define LL long long
struct A{
int x,y,k; LL z;
}a[N];
struct e{
int u,v,cap,next; LL cost;
}e[M*2];
int n,ans=0,num=1,S,T,head[N],pre[N],flow[N],q[M*4];
bool vis[N]; LL dis[N],sum=0;
inline int in(){
int x=0; char ch=getchar(); bool f=1;
while (ch<'0'||ch>'9'){
if (ch=='-') f=0;
ch=getchar();
}while (ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
if (!f) x=-x; return x;
}
inline LL Lin(){
LL x=0; char ch=getchar(); bool f=1;
while (ch<'0'||ch>'9'){
if (ch=='-') f=0;
ch=getchar();
}while (ch>='0'&&ch<='9')
x=x*10ll+(LL)(ch-'0'),ch=getchar();
if (!f) x=-x; return x;
}
inline void add(int u,int v,int cap,LL cost){
e[++num].u=u,e[num].v=v,e[num].cap=cap;
e[num].cost=cost,e[num].next=head[u],head[u]=num;
e[++num].u=v,e[num].v=u,e[num].cap=0;
e[num].cost=-cost,e[num].next=head[v],head[v]=num;
}
inline void divide(int xu){
int i,x=a[xu].x,y;
a[xu].k=0,y=sqrt(x);
for (i=2; i<=sqrt(x); i++){
while (!(x%i)) x/=i,a[xu].k++;
}if (x>1) a[xu].k++;
}
inline bool spfa(){
int i,u,v,h=0,t=1;
for (i=S; i<=T; i++)
vis[i]=0,dis[i]=limit;
LL minn=dis[0];
q[h]=S,dis[S]=0ll,flow[S]=inf,vis[S]=1;
while (h<t){
u=q[h%P],h++,vis[u]=0;
for (i=head[u]; i; i=e[i].next){
v=e[i].v;
if (e[i].cap>0&&dis[v]<dis[u]+e[i].cost){
dis[v]=dis[u]+e[i].cost,pre[v]=i;
flow[v]=min(flow[u],e[i].cap);
if (!vis[v]) q[t%P]=v,t++,vis[v]=1;
}
}
}if (dis[T]>minn) return true;
else return false;
}
int main(){
int i,j; n=in(),S=0,T=n+1;
for (i=1; i<=n; i++) a[i].x=in();
for (i=1; i<=n; i++) a[i].y=in();
for (i=1; i<=n; i++) a[i].z=Lin();
for (i=1; i<=n; i++){
divide(i);
if (a[i].k&1) add(S,i,a[i].y,0);
else add(i,T,a[i].y,0);
}for (i=1; i<=n; i++){
if (a[i].k&1){
for (j=1; j<=n; j++){
if (i==j) continue;
if (!(a[j].k&1)){
if (!(a[i].x%a[j].x)&&a[i].k==a[j].k+1)
add(i,j,inf,a[i].z*a[j].z);
if (!(a[j].x%a[i].x)&&a[j].k==a[i].k+1)
add(i,j,inf,a[i].z*a[j].z);
}
}
}
}while (spfa()){
if ((sum+dis[T]*flow[T])<0){
ans+=(int)(sum/(-dis[T])); break;
}else {
for (i=T; i!=S; i=e[pre[i]].u){
e[pre[i]].cap-=flow[T];
e[pre[i]^1].cap+=flow[T];
}ans+=flow[T],sum+=dis[T]*flow[T];
}
}printf("%d\n",ans);
return 0;
}
題目大意:
給出一棵n個節點的樹,每次操作選一條鏈,用一個自變數是和出發點的距離的一次函式更新最小值,多次詢問某條鏈的最小值。
題解:
據說這個題是李超樹,國家集訓隊作業題掛到了樹上(聽說
用線段樹維護覆蓋當前區間的線段,更新的時候分情況討論,如果可以更新就下傳當前線段,然後標記新線段,每次線段最多被分成
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100010
#define inf 123456789123456789ll
#define LL long long
#define root 1,1,n
#define lch rt<<1,l,mid
#define rch rt<<1|1,mid+1,r
struct E{
int v,next; LL k;
}e[N<<1];
struct Line{
LL k,b;
inline LL F(LL x){
return k*x+b;
}
};
struct Tr{
Line x; LL minn; bool f;
}tr[N<<2];
int n,m,num=0,tot=0,head[N],cur[N],fa[N][20],de[N],w[N],top[N],sz[N],son[N],q[N]; LL ans,dis[N],Dis[N];
inline int in(){
int x=0; char ch=getchar(); bool f=1;
while (ch<'0'||ch>'9'){
if (ch=='-') f=0;
ch=getchar();
}while (ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
if (!f) x=-x; return x;
}
inline LL Lin(){
LL x=0ll; char ch=getchar(); bool f=1;
while (ch<'0'||ch>'9'){
if (ch=='-') f=0;
ch=getchar();
}while (ch>='0'&&ch<='9')
x=x*10ll+(LL)(ch-'0'),ch=getchar();
if (!f) x=-x; return x;
}
inline void add(int u,int v,LL k){
e[++num].v=v,e[num].k=k;
e[num].next=head[u],head[u]=num;
}
inline void BFS(){
int i,j,u,v,h=0,t=1; q[h]=1,dis[1]=0;
for (i=1; i<=n; i++) cur[i]=head[i];
while (h<t){
u=q[h++];
for (i=1; (1<<i)<=de[u]; i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for (i=head[u]; i; i=e[i].next){
v=e[i].v; if (v==fa[u][0]) continue;
fa[v][0]=u,de[v]=de[u]+1;
dis[v]=dis[u]+e[i].k,q[t++]=v;
}
}for (i=t-1; i>=0; i--){
u=q[i],sz[u]=1,son[u]=0;
for (j=head[u]; j; j=e[j].next){
v=e[j].v; if (v==fa[u][0]) continue;
sz[u]+=sz[v]; if (sz[son[u]]<sz[v]) son[u]=v;
}
}for (i=0; i<t; i++){
u=q[i];
if (!w[u]){
for (j=u; j; j=son[j])
w[j]=++tot,Dis[tot]=dis[j],top[j]=u;
}
}
}
inline int lca(int x,int y){
if (de[x]<de[y]) swap(x,y);
int i,k=de[x]-de[y];
for (i=18; i>=0; i--)
if (k&(1<<i)) x=fa[x][i];
if (x==y) return x;
for (i=18; i>=0; i--)
if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
if (x==y) return x;
return fa[x][0];
}
inline void push_up(int rt){
tr[rt].minn=min(tr[rt].minn,min(tr[rt<<1].minn,tr[rt<<1|1].minn));
}
inline void build(int rt,int l,int r){
tr[rt].minn=inf,tr[rt].f=0;
if (l==r) return;
int mid=(l+r)>>1;
build(lch),build(rch);
push_up(rt);
}
inline void change(int rt,int l,int r,int ll,int rr,Line x){
if (ll<=l&&r<=rr){
tr[rt].minn=min(tr[rt].minn,min(x.F(Dis[l]),x.F(Dis[r])));
if (!tr[rt].f){
tr[rt].f=1,tr[rt].x=x;
return;
}if (l==r){
if (x.F(Dis[l])<tr[rt].x.F(Dis[l])) tr[rt].<