http://codeforces.com/gym/101078

和ysy、方老师一起打的virtual

Codeforces Training S03E01泛做-LMLPHP

打的不是很好...下面按过题顺序放一下过的题的题(dai)解(ma)。

A

给两个1~n的排列,把它们割成尽量短的一些段,使得每一段sort之后一样。

随便写个hash了事(1min交是因为之前顺手写了这题)

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
using namespace std;
#define pb push_back
#define mp make_pair
typedef pair<int,int> pii;
typedef long long ll;
typedef double ld;
typedef vector<int> vi;
#define fi first
#define se second
#define fe first
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");}
#ifdef LOCAL
#define TIMER cerr<<clock()<<"ms\n"
#else
#define TIMER
#endif
#define SZ 666666
int n,a[SZ],b[SZ];
int main()
{
int T; scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i);
for(int i=1;i<=n;i++) scanf("%d",b+i);
int ca1=0,ca2=0,ca3=1,cb1=0,cb2=0,cb3=1;
int lst=0;
for(int i=1;i<=n;i++)
{
ca1+=a[i]; cb1+=b[i];
ca2^=a[i]; cb2^=b[i];
ca3*=a[i]+(233^n)+666; cb3*=b[i]+(233^n)+666;
if(ca1!=cb1||ca2!=cb2||ca3!=cb3);else
{
printf("%d-%d ",lst+1,i); lst=i;
ca1=0,ca2=0,ca3=1,cb1=0,cb2=0,cb3=1;
}
}
puts("");
}
}

D

有一排洞,从1开始左到右编号,对于每个m,如果m是偶数,那么m和m/2有一条绳子相连,如果m是奇数,m与3m+1有一条绳子相连。

现在在n和n+1这两个洞中间劈一刀,问会砍断多少条绳子。

推推公式...ysy写的

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
int t,n;
inline int s(int l,int r)
{
if(!(l&1))
l++;
if(!(r&1))
r--;
return (r-l)/2+1;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
printf("%d\n",n-n/2+s((n-1)/3+1,n));
}
return 0;
}

L

有一个01串,现在要通过交换变成前面全是0,后面全是1。

交换i、j,i<=j需要sqrt(j-i)的代价,求最小代价。

注意到(目测出)sqrt(a+b+c)+sqrt(b)<sqrt(a+b)+sqrt(b+c)(因为sqrt增长越来越慢),那么我们只要倒着暴力枚举,能换就换。

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
using namespace std;
#define pb push_back
#define mp make_pair
typedef pair<int,int> pii;
typedef long long ll;
typedef double ld;
typedef vector<int> vi;
#define fi first
#define se second
#define fe first
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");}
#ifdef LOCAL
#define TIMER cerr<<clock()<<"ms\n"
#else
#define TIMER
#endif
#define SZ 666666
char s[SZ];
char ep[SZ];
int n;
int main()
{
scanf("%s",s);
n=strlen(s);
int zero=0;
for(int i=0;i<n;i++) zero+=s[i]=='0';
for(int i=0;i<n;i++) ep[i]=(i>=zero)+48;
double ans=0;
for(int i=0;i<n;i++)
{
if(s[i]==ep[i]) continue;
for(int j=n-1;j>=i+1;j--)
{
if(s[j]!=ep[i]) continue;
swap(s[i],s[j]);
ans+=sqrt(j-i);
break;
}
}
printf("%.11lf\n",ans);
}

C

有一个3*3*n的立方体,每一块可以和相邻块匹配,求全部匹配上的方案数。

十分难写的状压dp,ysy码的

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
int t,n,f[5010][600],g[600][600],a[600][600],x[10][10],q=10007;
inline int dfs(int i,int j)
{
if(i>3)
return 1;
if(j>3)
return dfs(i+1,1);
if(!x[i][j])
return dfs(i,j+1);
int p=0;
if(x[i][j+1])
{
x[i][j]=0;
x[i][j+1]=0;
p+=dfs(i,j+1);
x[i][j]=1;
x[i][j+1]=1;
}
if(x[i+1][j])
{
x[i][j]=0;
x[i+1][j]=0;
p+=dfs(i,j+1);
x[i][j]=1;
x[i+1][j]=1;
}
return p;
}
inline void js(int n,int m)
{
int i,j;
for(i=0;i<9;i++)
if((n&(1<<i)) && (m&(1<<i)))
return;
else if((n&(1<<i)) || (m&(1<<i)))
x[i/3+1][i%3+1]=0;
else
x[i/3+1][i%3+1]=1;
g[n][m]=dfs(1,1);
a[n][++a[n][0]]=m;
}
int main()
{
int i,j,k;
n=5000;
for(i=0;i<512;i++)
for(j=0;j<512;j++)
js(i,j);
f[0][0]=1;
for(i=1;i<=n;i++)
for(j=0;j<512;j++)
for(k=1;k<=a[j][0];k++)
f[i][a[j][k]]=(f[i][a[j][k]]+f[i-1][j]*g[j][a[j][k]])%q;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
printf("%d\n",f[n][0]);
}
return 0;
}

F

交互库走迷宫,最后输出最短路径。

一波dfs即可,注意细节。

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
using namespace std;
#define pb push_back
typedef pair<int,int> pii;
typedef long long ll;
typedef double ld;
typedef vector<int> vi;
#define fi first
#define se second
#define fe first
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");}
#ifdef LOCAL
#define TIMER cerr<<clock()<<"ms\n"
#else
#define TIMER
#endif
#define SZ 666666
int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
int npp[233];
bool mp[233][233][5];
int ex=-1,ey=-1;
bool vis[233][233];
char tmp[2333],fm[]={"NSEW"};
#define P 101
bool& Vis(int a,int b)
{
return vis[a+P][b+P];
}
bool* Mp(int a,int b)
{
return mp[a+P][b+P];
}
#define FFF fflush(NULL);
void dfs(int x,int y)
{
Vis(x,y)=1;
scanf("%s",tmp);
for(int i=0;tmp[i];i++)
{
if(tmp[i]=='*')
{
ex=x; ey=y;
}
else Mp(x,y)[npp[tmp[i]]]=1;
}
for(int i=0;i<4;i++)
{
if(!Mp(x,y)[i]) continue;
if(Vis(x+dx[i],y+dy[i])) continue;
printf("%c\n",fm[i]); FFF
dfs(x+dx[i],y+dy[i]);
printf("%c\n",fm[i^1]); FFF
scanf("%s",tmp);
}
}
pii ps[SZ];
int dis[233][233];
int& Dis(int a,int b)
{
return dis[a+P][b+P];
}
void bfs()
{
memset(dis,127/3,sizeof(dis));
int inf=dis[0][0];
int h=0,t=0;
Dis(0,0)=0; ps[t++]=pii(0,0);
while(h^t)
{
pii x=ps[h++];
for(int k=0;k<4;k++)
{
if(!Mp(x.fi,x.se)[k]) continue;
if(Dis(x.fi+dx[k],x.se+dy[k])!=inf) continue;
Dis(x.fi+dx[k],x.se+dy[k])=Dis(x.fi,x.se)+1;
ps[t++]=pii(x.fi+dx[k],x.se+dy[k]);
}
}
}
int T;
int main()
{
npp['N']=0; npp['S']=1; npp['E']=2; npp['W']=3;
scanf("%d",&T);
while(T--)
{
ex=-2333, ey=-2333;
memset(mp,0,sizeof(mp));
memset(vis,0,sizeof(vis));
dfs(0,0);
if(ex==-2333)
{
puts("-1"); FFF
continue;
}
memset(vis,0,sizeof(vis));
bfs();
printf("%d\n",Dis(ex,ey)); FFF
}
}

I

叫你写一个编辑器,可以指针左移,指针右移,打一个字母。

写个链表,方老师写的。

# include <stdio.h>
# include <string.h>
using namespace std; int test;
char str[1300000]; int pre[1300000], nxt[1300000], s[1300000], cur=0, siz=0, sz=0; int main() {
scanf("%d", &test);
while(test--) {
for (int i=0; i<=1000000; ++i) pre[i]=nxt[i]=s[i]=0;
cur=0,siz=0,sz=0;
scanf("%s", str);
sz=strlen(str);
for (int i=0; i<sz; ++i) {
if(str[i] == '<') {
if(cur != 0) cur = pre[cur];
}
else if(str[i] == '>') {
if(nxt[cur] != 0) cur = nxt[cur];
} else if(str[i] == '-') {
if(cur) {
nxt[pre[cur]] = nxt[cur];
pre[nxt[cur]] = pre[cur];
cur = pre[cur];
}
} else {
++siz;
nxt[siz] = nxt[cur];
pre[siz] = cur;
nxt[cur] = siz;
int NEXT = nxt[siz];
pre[NEXT] = siz;
s[siz] = str[i];
cur=siz;
}
}
int pos = nxt[0];
while(pos != 0) {
printf("%c", (char)s[pos]);
pos=nxt[pos];
}
puts("");
}
}

E

w*h的矩形内有c个圆,给定圆心半径,圆两两不相交(可能相离、相切),求矩形内一个最大的圆使得与任何给定圆不交,输出半径,相对/绝对误差1e-6。

瞎退火,似乎调参挺蛋疼的,ysy写的。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<time.h>
using namespace std;
int t,a,b,n,x[51],y[51],r[51];
double sx,sy,sr,tx[1000],ty[1000],tr[1000],p;
int main()
{
srand(time(NULL));
int i,j,l;
double k,q;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&a,&b,&n);
for(i=1;i<=n;i++)
scanf("%d%d%d",&x[i],&y[i],&r[i]);
p=0;
for(i=1;i<=10;i++)
{
sx=double(((rand()<<15)+rand())%(10*a+1))/10;
sy=double(((rand()<<15)+rand())%(10*b+1))/10;
sr=min(min(sx,a-sx),min(sy,b-sy));
for(j=1;j<=n;j++)
sr=min(sr,sqrt((sx-x[j])*(sx-x[j])+(sy-y[j])*(sy-y[j]))-r[j]);
for(k=1e6;k>1e-9;k*=0.9)
{
for(l=1;l<=10;l++)
{
q=double(((rand()<<15)+rand())%6283)/1000;
tx[l]=sx+k*sin(q);
ty[l]=sy+k*cos(q);
tx[l]=min(max(tx[l],0.0),double(a));
ty[l]=min(max(ty[l],0.0),double(b));
tr[l]=min(min(tx[l],a-tx[l]),min(ty[l],b-ty[l]));
for(j=1;j<=n;j++)
tr[l]=min(tr[l],sqrt((tx[l]-x[j])*(tx[l]-x[j])+(ty[l]-y[j])*(ty[l]-y[j]))-r[j]);
}
for(l=1;l<=10;l++)
if(tr[l]>sr)
{
sx=tx[l];
sy=ty[l];
sr=tr[l];
}
}
p=max(p,sr);
}
printf("%.9lf\n",p);
}
return 0;
}

J

给出一个填字游戏,有横着的和竖着的,横着的互相不交,竖着的互相不交,现在填上去发现横竖有一些交叉的地方不一样,不能共存。于是让你求出最多的可以共存的。

把不能共存的连边,就是要求二分图最大独立集。n-最大匹配即可。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <limits>
#include <set>
#include <map>
using namespace std;
namespace gg
{
#define SZ 666666
int n,M=1;typedef long long ll;
int fst[SZ],nxt[SZ],vb[SZ],cap[SZ];
void _ad_dl(int a,int b,int c) {++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;cap[M]=c;}
void ad_dl(int a,int b,int c) {_ad_dl(a,b,c); _ad_dl(b,a,0);}
int S,T,q[SZ],d[SZ];
bool bfs()
{
for(int i=1;i<=n+1;i++) d[i]=-1;
d[S]=0; q[1]=S; int h=1,t=2;
while(h!=t)
{
int cur=q[h++];
for(int e=fst[cur];e;e=nxt[e])
{
int b=vb[e];
if(d[b]==-1&&cap[e]) d[b]=d[cur]+1, q[t++]=b;
}
}
return d[T]!=-1;
}
int dfs(int x,int f)
{
if(f<=0) return 0;
if(x==T) return f;
int ca=0;
for(int e=fst[x];e;e=nxt[e])
{
int b=vb[e];
if(d[b]!=d[x]+1) continue;
int w=dfs(b,min(cap[e],f-ca));
cap[e]-=w; cap[e^1]+=w; ca+=w;
if(ca==f) break;
}
if(!ca) d[x]=-1;
return ca;
}
#define inf 1000000000
int dinic()
{
int ans=0;
while(bfs()) ans+=dfs(S,inf);
return ans;
}
int Tat,h,v,x1[SZ],y1[SZ],x2[SZ],y2[SZ];
int s1l[SZ],s2l[SZ];
char s1[503][1003],s2[503][1003];
int main()
{
//freopen("test.txt","r",stdin);
scanf("%d",&Tat);
while(Tat--)
{
M=1;
scanf("%d%d",&h,&v);
for(int i=1;i<=h;i++)
{
scanf("%d%d ",x1+i,y1+i);
gets(s1[i]);
s1l[i]=strlen(s1[i]);
}
for(int i=1;i<=v;i++)
{
scanf("%d%d ",x2+i,y2+i);
gets(s2[i]);
s2l[i]=strlen(s2[i]);
}
n=h+v; S=++n; T=++n;
for(int i=1;i<=n;i++) fst[i]=0;
for(int i=1;i<=h;i++) ad_dl(S,i,1);
for(int i=1;i<=v;i++) ad_dl(i+h,T,1);
for(int i=1;i<=h;i++)
{
for(int j=1;j<=v;j++)
{
int xx=x2[j],yy=y1[i];
bool ok=1;
if(x1[i]<=xx&&xx<=x1[i]+s1l[i]-1)
{
if(y2[j]<=yy&&yy<=y2[j]+s2l[j]-1)
{
if(s1[i][xx-x1[i]]==s2[j][yy-y2[j]])
ok=1;
else ok=0;
}
}
//cout<<i<<","<<j<<" "<<ok<<"\n";
if(!ok) ad_dl(i,j+h,1);
}
}
printf("%d\n",h+v-dinic());
}
}
}
int main()
{
gg::main();
}

接下来就卡题了...打出gg

05-02 05:26