codevs第三次月赛
T1正解,T2部分分,T3迭代深搜……
结果:T1:100,T2:40,T3:40
rank25…其实T3的想法挺接近70分算法的,然而我还是打的暴力…还是太弱
T1:Cww的作业
打表可得:fn=n/2(下取整)
于是答案是2∑k^2(1<=k<=n)%10007
公式可知,答案是(n(n+1)(2n+1)/3) %10007
带除法的模,要求3的逆元,也就是求3x=1(%10007)
的x,可以暴力for,也可以exgcd。
或者不用求逆元,n or n+1 or 2n+1
其中必有一个为3的倍数,找出来先除了再模也可以。
据说把n先模10007可以(玄学?)??我没试
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const long long mod=10007;
int main()
{
long long n;
scanf("%lld",&n);
printf("%lld",( (n%mod) * ((n+1)%mod) * ((2ll*n+1)%mod) *3336ll)%10007);
return 0;
}
T2:逃离异次元杀阵
第一眼看:树,仙人掌,仙人掌加一条边…
然后就交了个倍增LCA,30分跑的暴力,拿40滚粗…
结果正解看起来好傻X…以下来自官方题解:
对于M=N的数据,考虑在原算法上进行修改。可以拆掉一条边使得其变为一棵树,设拆掉的边为x—y,权值为s,则依然按上述做法求解,则最终的答案是min{dis(i,j),dis(i,x)+s+dis(y,j),dis(i,y)+s+dis(x,j)}。拆边可以用各种方法完成。
对于M=N+1的数据,不过是多拆了一条边,不过是上述算法的加强版。设拆掉两条x1—y1,边权s1,x2—y2,边权s2,则答案是
min{
Dis(i,j)
Dis(i,x1)+s1+dis(y1,j)
Dis(i,x2)+s1+dis(y2,j)
Dis(i,y1)+s1+dis(x1,j)
Dis(i,y2)+s1+dis(x2,j)
Dis(i,x1)+s1+dis(y1,x2)+s2+dis(y2,j)
Dis(i,y1)+s1+dis(x1,x2)+s2+dis(y2,j)
Dis(i,x1)+s1+dis(y1,y2)+s2+dis(x2,j)
Dis(i,y1)+s1+dis(x1,y2)+s2+dis(x2,j)
Dis(i,x2)+s2+dis(y2,x1)+s1+dis(y1,j)
Dis(i,y2)+s2+dis(x2,x1)+s1+dis(y1,j)
Dis(i,x2)+s2+dis(y2,y1)+s1+dis(x1,j)
Dis(i,y2)+s2+dis(x2,y1)+s1+dis(x1,j)
}
时间复杂度是O(nlogn+13q)
滚粗代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int size=100010;
int head[size],nxt[size],dist[size],anc[size][32];
int tot=0;
int deep[size];
struct edge{
int t,d;
}l[size];
void build(int f,int t,int d)
{
l[++tot]=(edge){t,d};
nxt[tot]=head[f];
head[f]=tot;
}
void dfs(int u,int fa)
{
if(deep[u]) return ;
deep[u]=deep[fa]+1;
anc[u][0]=fa;
for(int i=1;anc[anc[u][i-1]][i-1];i++)
{
anc[u][i]=anc[anc[u][i-1]][i-1];
}
for(int i=head[u];i;i=nxt[i])
{
int v=l[i].t;
if(!deep[v]) dist[v]=dist[u]+l[i].d;
dfs(v,u);
}
}
int asklca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
if(deep[x]>deep[y])
{
int dd=deep[x]-deep[y];
for(int i=0;i<=28;i++)
{
if((1<<i)&dd)
{
x=anc[x][i];
}
}
}
if(x!=y)
{
for(int i=28;i>=0;i--)
{
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
}
}
if(x==y) return x;
else return anc[x][0];
}
bool use[size];
queue<int> q;
void spfa(int s)
{
memset(dist,63,sizeof(dist));
dist[s]=0;
use[s]=1;
q.push(s);
while(q.size())
{
int f=q.front(); q.pop();
use[f]=0;
for(int i=head[f];i;i=nxt[i])
{
int v=l[i].t;
if(dist[v]>dist[f]+l[i].d)
{
dist[v]=dist[f]+l[i].d;
if(!use[v])
{
use[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
build(a,b,c);
build(b,a,c);
}
if(n<=2000)
{
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
spfa(x);
printf("%d\n",dist[y]);
}
return 0;
}
if(m==n-1)
{
dfs(1,0);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
int lca=asklca(x,y);
printf("%d\n",dist[x]-dist[lca]+dist[y]-dist[lca]);
}
return 0;
}
else if(m==n)
{
}
else
{
}
return 0;
}
感觉没错但交上去WA一个点的代码……有点迷,不懂,求神犇打脸QAQ
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int size=100010;
int head[size],nxt[size],anc[size][30],deep[size],dist[size];
int tot=0;
struct edge{
int t,d;
}l[size];
int n,m,q;
void build(int f,int t,int d)
{
l[++tot]=(edge){t,d};
nxt[tot]=head[f];
head[f]=tot;
}
void dfs(int u,int fa)
{
if(deep[u]>0) return ;
deep[u]=deep[fa]+1;
anc[u][0]=fa;
for(int i=1;anc[anc[u][i-1]][i-1];i++)
{
anc[u][i]=anc[anc[u][i-1]][i-1];
}
for(int i=head[u];i;i=nxt[i])
{
int v=l[i].t;
if(deep[v]==0) dist[v]=dist[u]+l[i].d;
dfs(v,u);
}
}
int asklca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
if(deep[x]>deep[y])
{
int dd=deep[x]-deep[y];
for(int i=0;i<=24;i++)
{
if(dd&(1<<i))
{
x=anc[x][i];
}
}
}
if(x!=y)
{
for(int i=24;i>=0;i--)
{
if(anc[x][i]!=anc[y][i])
{
x=anc[x][i];
y=anc[y][i];
}
}
}
if(x==y) return x;
else return anc[x][0];
}
int ask(int x,int y)
{
int lca=asklca(x,y);
return dist[x]-dist[lca]+dist[y]-dist[lca];
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n-1;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
build(a,b,c);
build(b,a,c);
}
dfs(1,0);
if(m==n-1)
{
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",ask(x,y));
}
}
else if(m==n)
{
int x1,y1,d1;
scanf("%d%d%d",&x1,&y1,&d1);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",min(ask(x,y),min( ask(x,x1)+d1+ask(y1,y) ,ask(x,y1)+d1+ask(x1,y) ) ) );
}
}
else
{
int x1,y1,d1,x2,y2,d2;
scanf("%d%d%d",&x1,&y1,&d1);
scanf("%d%d%d",&x2,&y2,&d2);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
int ans1=min( min( ask(x,x1)+d1+ask(y1,y) ,ask(x,y1)+d1+ask(x1,y) ) , min( ask(x,x2)+d2+ask(y2,y) , ask(x,y2)+d2+ask(x2,y) ) );
int ans2=min( min( ask(x,x1)+d1+ask(y1,x2)+d2+ask(y2,y) , ask(x,x1)+d1+ask(y1,y2)+d2+ask(x2,y) ) , min( ask(x,x2)+d2+ask(y2,x1)+d1+ask(y1,y) , ask(x,x2)+d2+ask(y2,y1)+d1+ask(x1,y) ) );
int ans3=min( min( ask(x,y1)+d1+ask(x1,x2)+d2+ask(y2,y) , ask(x,y1)+d1+ask(x1,y2)+d2+ask(x2,y) ) , min( ask(x,y2)+d2+ask(x2,x1)+d1+ask(y1,y) , ask(x,y2)+d2+ask(x2,y1)+d1+ask(x1,y) ) );
int ans4=ask(x,y);
printf("%d\n",min(min(ans1,ans2),min(ans3,ans4)));
}
}
return 0;
}
/*
x1-----y1 x2-----y2
x1 y1 x2 y2 x1 y1 y2 x2
y1 x1 x2 y2 y1 x1 y2 x2
x2 y2 x1 y1 x2 y2 y1 x1
y2 x2 x1 y1 y2 x2 y1 x1
*/
T3:破坏
对偶图?什么鬼
我打的迭代深搜,期望得分0~40,结果数据给的暴力分还可以,于是拿了40
正解(以下来自codevs官方题解):
首先看第一个点,显然我们要做到把所有未破坏的点都破坏掉,排序+去重求出有t个不重复的格子已经被破坏,则答案是m-t。
再看第二个点,显然只要任一个格子已经被破坏就可以了。如果k不为0则答案就是0,否则答案就是1。
然后看3,4,5三个点,可以暴力搜索每个格子是否破坏,然后暴力判断是否符合。综合以上能得到25分。
对于6,7,8三个点,可以用一些比较好的暴力然后剪一剪枝。
对于9~20十二个点:
首先有一个很重要的结论:未破坏的格子最上面与最下面不四连通,等价于,已破坏的格子最左面与最右面八连通。(似乎是对偶图性质?)接下来提到的联通和一步都是指八方向的。
我们要添加一些点使得左侧和右侧能联通,对于n,m<=1000的9~14六个点我们想到宽搜,所有原先已被破坏的联通块视为等价点,从左侧开始,每一步的代价是1,宽搜到右侧,等价点就是指当宽搜到某个已被破坏的点时,将所有等价点也就是该格子所在的联通块的全部格子全部赋为等值。
对于n,m很大但是k<=1000的15~20六个点就要有别的方法。考虑两个格子(x1,y1),(x2,y2),要将它们联通,代价应该是max{|x1-x2|-1,|y1-y2|-1,0}。要把(x,y)(第x行第y列)和左侧联通,代价为y-1。要把它和右侧联通,代价为m-y。这样做一遍从左侧到右侧的最短路即可,复杂度为O(k^2)。
本题要结合两种算法和两个小判断来做。
题解好像把9~14和15~20搞反了,不过无所谓233
正解条了半天没调出来……还是太弱,40分代码(跟没调出来的程序对拍发现好像有错…):
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<cstdlib>
using namespace std;
const int size=1010;
const int dx[]={0,-1,0,1,0};
const int dy[]={0,0,1,0,-1};
int maps[size][size];
int n,m,k;
int deep;
struct xy{
int x,y;
};
queue<xy> q;
bool vis[size][size];
bool bfs(int x,int y)
{
while(q.size()) q.pop();
memset(vis,0,sizeof(vis));
q.push((xy){x,y});
vis[x][y]=1;
while(q.size())
{
xy f=q.front(); q.pop();
if(f.x==n) return false;
for(int i=1;i<=4;i++)
{
int nx=f.x+dx[i];
int ny=f.y+dy[i];
if(nx>0&&nx<=n&&ny>0&&ny<=m&&!vis[nx][ny]&&!maps[nx][ny])
{
vis[nx][ny]=1;
q.push((xy){nx,ny});
}
}
}
return true;
}
void dfs(int x,int y,int d)
{
if(d>deep) return ;
if(d==deep)
{
int t=0;
for(int i=1;i<=m;i++)
if(bfs(1,i)) t++;
if(t==m)
{
/* for(int xx=1;xx<=n;xx++) { for(int yy=1;yy<=m;yy++) { cout<<maps[xx][yy]<<" "; } puts(""); }*/
printf("%d\n",deep);
exit(0);
}
return ;
}
if(x==n+1) return ;
for(int i=x;i<=n;i++)
{
for(int j=1;j<=m;j++)
if(!maps[i][j])
{
if(i==x&&j<y) continue;
maps[i][j]=1;
if(j==m) dfs(i+1,1,d+1);
else dfs(i,j+1,d+1);
maps[i][j]=0;
}
}
}
map<int,bool> h;
int main()
{
scanf("%d%d%d",&n,&m,&k);
{
if(k==0)
{
printf("%d",m);
return 0;
}
if(n==1)
{
int tot=0;
for(int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(!h[y]) {tot++;h[y]=1;}
}
printf("%d\n",m-tot);
return 0;
}
else if(m==1)
{
if(!k) puts("1");
else puts("0");
return 0;
}
}
for(int i=1;i<=k;i++)
{
int x,y;
scanf("%d%d",&x,&y);
maps[x][y]=1;
}
for(deep=0;deep<=m;deep++)
{
dfs(1,1,0);
}
return 0;
}
正解先挖坑,以后再填