部分题解是指没写那道算几。
BZOJ上目前没有day2的题面D2T2的图。
BZOJ4813 小Q的棋盘
显然可以$O(n^2)$DP,然而可以$O(n)$贪心:只有一条从根出发的一条链上的边可以只经过一次,其他边如果被经过则必须经过两次,且次数没用完时一定可以用来经过没被经过的边,那么只用枚举那条链的端点。
感觉和SCOI D1T1神似:$O(n^2)$树形DP显然,然而可以$O(n)$贪心。只不过SCOI DP过不了
#include
struct node;
typedef struct node edge;
struct node{
int v;
edge*s;
}e[198];
edge*l=e,*h[100];
void ins(int u,int v){
edge s={v,h[u]};
*(h[u]=l++)=s;
}
int n,m,u,v,a,d[100];
void dfs(int u,int j){
if(m>=d[u]){
if(a>1)
a=d[u]+m+2>>1;
for(edge*i=h[u];i;i=i->s)
if(i->v!=j)
d[i->v]=d[u]+1,dfs(i->v,u);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i
BZOJ4815 小Q的表格
设$\gcd(a,b)=d$,则$f(a,b)=\frac{ab}{d^2}f(d,d)$。
\begin{align*}&\sum_{d=1}^nf(d,d)\sum_{i=1}^{\left\lfloor\frac nd\right\rfloor}\sum_{j=1}^{\left\lfloor\frac nd\right\rfloor}ij[(i,j)=1]\\=&\sum_{d=1}^nf(d,d)\sum_{i=1}^{\left\lfloor\frac nd\right\rfloor}i^2\varphi(i)\end{align*}
分块维护一下$f(d,d)$就好了,复杂度$O(n+m\sqrt{n})$。
#include
#include
typedef unsigned long long ll;
const int p=1e9+7;
const int N=4e6+5;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
inline int foo(int x){
return xbs?foo(c3[x]+c4[b[x]]):c3[x];
}
void cov(int x,int y){
int d=bar(y-bar(ask(x)-ask(x-1)));
for(int i=x;i<=c2[b[x]];++i)
inc(c3[i],d);
for(int i=b[x]+1;i<=nb-1;++i)
inc(c4[i],d);
}
int main(){
scanf("%d%d",&m,&n);
bs=sqrt(n+.5)*3/2;
for(int i=1;i<=n;++i)
b[i]=(i-1)/bs;
nb=b[n]+1;
for(int i=1;i<=n;++i)
c2[b[i]]=i;
for(int i=n;i>=1;--i)
c1[b[i]]=i;
for(int i=1;i<=n;++i){
c3[i]=(ll)i*i%p;
inc(c4[b[i]+1],c3[i]);
if(i!=c1[b[i]])
inc(c3[i],c3[i-1]);
}
for(int i=1;in)break;
if(i%*j==0){
f[i**j]=(ll)*j**j**j%p*f[i]%p;
break;
}
f[i**j]=(ll)f[i]*f[*j]%p;
}
}
for(int i=2;i<=n;++i)
inc(f[i],f[i-1]);
while(m--){
int x,y;
ll z;
scanf("%d%d%lld%d",&x,&y,&z,&n);
int d=gcd(x,y);
cov(d,z/(x/d)/(y/d)%p);
int i=1,s=0;
while(i<=n){
int j=n/(n/i);
s=(s+(ll)bar(f[j]-f[i-1])*ask(n/i))%p;
i=j+1;
}
printf("%d\n",s);
}
}
BZOJ4822 老C的任务
签到题。
和SCOI D2T1神似:NOIP难度以下签到题。只不过SCOI有人被卡常数T了5分
#include
#define lb lower_bound
#define ub upper_bound
#define pb push_back
using namespace std;
typedef long long ll;
const int N=1e5+5;
struct node{
node*i,*j;
ll s;
}e[N*20];
node*l=e,*r[N];
void ins(int z,int y,node**o){
for(int i=16;~i;--i){
*++l=**o,*o=l;
if(y>>i&1)o=&(*o)->j;
else
(*o)->s+=z,o=&(*o)->i;
}
}
ll ask(int y,node*s,node*t){
ll z=0;
for(int i=16;~i;--i)
if(~y>>i&1)s=s->i,t=t->i;
else
z+=t->s-s->s,s=s->j,t=t->j;
return z;
}
int n,m,s,t,u,v,x[N],y[N],z[N],a[N],b[N];
vectorc[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i
BZOJ4823 老C的方块
设特殊边两边的方块为灰色,这两个方块的其他相邻方块分别为黑色和白色,可以将整个棋盘染色。当两个灰色方块同时存在时,相邻的其他方块只能有一种颜色,那么容易建立最小割模型,S向所有黑色方块连边,所有白色方块向T连边,容量为权值;灰色方块与相邻的黑色或白色方块连边,容量为无穷大;两个灰色方块之间连边,容量为两个方块权值的较小值。
#include
using namespace std;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int N=1e5+5;
const int inf=1061109567;
struct edge{
int v,c;
edge*s;
}e[N*8];
edge*l=e,*h1[N],*h2[N];
void ins(int u,int v,int c){
edge a={v,c,h1[u]};
edge b={u,0,h1[v]};
*(h1[u]=l++)=a;
*(h1[v]=l++)=b;
}
int s1,s2,d[N],q[N];
int dfs(int u,int c){
if(u==s2)return c;
int f=0;
for(edge*&i=h2[u];i;i=i->s)
if(d[u]+1==d[i->v]&&i->c){
int v=dfs(i->v,min(c-f,i->c));
i->c-=v;
e[i-e^1].c+=v;
f+=v;
if(f==c)break;
}
if(!f)d[u]=-1;
return f;
}
int bfs(){
int f=0;
for(;;f+=dfs(s1,inf)){
fill(d,d+s2+1,-1);
d[q[0]=s1]=0;
for(int a=0,b=0;a<=b;++a){
int u=q[a];
for(edge*i=h2[u]=h1[u];i;i=i->s)
if(!~d[i->v]&&i->c)
d[q[++b]=i->v]=d[u]+1;
}
if(!~d[s2])return f;
}
}
int jud(int x,int y){
int a=x&1,b=y&3;
return a&&!b||!a&&b==1?0:a&&b==3||!a&&b==2?1:a&&b==1||!a&&!b?2:3;
}
mapf[N];
int n,x[N],y[N],w[N];
int main(){
scanf("%*d%*d%d",&n),s1=n,s2=n+1;
for(int i=0;i::iterator k=f[nx].find(ny);
if(k!=f[nx].end())
if(!z)
ins(k->second,i,inf);
else if(z==1)
ins(i,k->second,inf);
else if(z==3)
ins(i,k->second,min(w[i],w[k->second]));
}
}
printf("%d\n",bfs());
}
BZOJ4824 老C的键盘
把BZOJ3167粘过来改改就好了。
#include
#include
using namespace std;
typedef unsigned long long ll;
const int p=1e9+7;
const int N=100;
ll f[N][N],g[N],c[N][N];
int n,e[N][N],r[N];
void dfs(int u,int l){
r[u]=f[u][0]=1;
for(int v=0;v