USACO FALL 2003 题目

MS官网上没有了。。。
发这吧。。。
**********************************************************************
GREEN PROBLEMS
**********************************************************************
Four problems numbered 1 through 4
**********************************************************************

PROBLEM 1: Cow Exhibition [Brian Jacokes, 2003]

"Fat and docile, big and dumb, they look so stupid, they aren’t much
fun…"
– Cows with Guns by Dana Lyons

The cows want to prove to the public that they are both smart and fun.
In order to do this, Bessie has organized an exhibition that will be put
on by the cows. She has given each of the N (1 <= N <= 100) cows a
thorough interview and determined two values for each cow: the smartness
Si (-1000 <= Si <= 1000) of the cow and the funness Fi (-1000 <= Fi <=
1000) of the cow.

Bessie must choose which cows she wants to bring to her exhibition. She
believes that the total smartness TS of the group is the sum of the Si’s
and, likewise, the total funness TF of the group is the sum of the Fi’s.
Bessie wants to maximize the sum of TS and TF, but she also wants both of
these values to be non-negative (since she must also show that the cows
are well-rounded; a negative TS or TF would ruin this). Help Bessie
maximize the sum of TS and TF without letting either of these values
become negative.

PROBLEM NAME: smrtfun

INPUT FORMAT:

* Line 1: A single integer N, the number of cows

* Lines 2..N+1: Two space-separated integers Si and Fi, respectively
the smartness and funness for each cow.

SAMPLE INPUT (file smrtfun.in):

5
-5 7
8 -6
6 -3
2 1
-8 -5

OUTPUT FORMAT:

* Line 1: One integer: the optimal sum of TS and TF such that both TS
and TF are non-negative. If no subset of the cows has
non-negative TS and non- negative TF, print 0.

SAMPLE OUTPUT (file smrtfun.out):

8

OUTPUT DETAILS:

Bessie chooses cows 1, 3, and 4, giving values of TS = -5+6+2 = 3 and TF
= 7-3+1 = 5, so 3+5 = 8. Note that adding cow 2 would improve the value
of TS+TF to 10, but the new value of TF would be negative, so it is not
allowed.

**********************************************************************

PROBLEM 2: Milking Grid [Tom Widland, 2003]

Every morning when they are milked, the Farmer John’s cows form a
rectangular grid that is R (1 <= R <= 10,000) rows by C (1 <= C <=
75) columns. As we all know, Farmer John is quite the expert on cow
behavior, and is currently writing a book about feeding behavior in
cows. He notices that if each cow is labeled with an uppercase letter
indicating its breed, the two-dimensional pattern formed by his cows
during milking sometimes seems to be made from smaller repeating
rectangular patterns.

Help FJ find the rectangular unit of smallest area that can be
repetitively tiled to make up the entire milking grid. Note that the
dimensions of the small rectangular unit do not necessarily need to
divide evenly the dimensions of the entire milking grid, as indicated
in the sample input below.

PROBLEM NAME: mgrid

INPUT FORMAT:

* Line 1: Two space-separated integers: R and C

* Lines 2..R+1: The grid that the cows form, with an uppercase letter
denoting each cow’s breed. Each of the R input lines has C
characters with no space or other intervening character.

SAMPLE INPUT (file mgrid.in):

2 5
ABABA
ABABA

OUTPUT FORMAT:

* Line 1: The area of the smallest unit from which the grid is formed

SAMPLE OUTPUT (file mgrid.out):

2

OUTPUT DETAILS:

The entire milking grid can be constructed from repetitions of the
pattern ‘AB’.

**********************************************************************

PROBLEM 3: Popular Cows [Brian Dean, 2003]

Every cow’s dream is to become the most popular cow in the herd. In a
herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <=
50,000) ordered pairs of the form (A, B) that tell you that cow A thinks
that cow B is popular. Since popularity is transitive, if A thinks B is
popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in
the input. Your task is to compute the number of cows that are
considered popular by every other cow.

PROBLEM NAME: popular

INPUT FORMAT:

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A
thinks B is popular.

SAMPLE INPUT (file popular.in):

3 3
1 2
2 1
2 3

OUTPUT FORMAT:

* Line 1: A single integer that is the number of cows who are
considered popular by every other cow.

SAMPLE OUTPUT (file popular.out):

1

OUTPUT DETAILS:

Cow 3 is the only cow of high popularity.

**********************************************************************

PROBLEM 4: Beauty Contest [Quynh Tran, 2003]

Bessie, Farmer John’s prize cow, has just won first place in a bovine
beauty contest, earning the title ‘Miss Cow World’. As a result, Bessie
will make a tour of N (2 <= N <= 50,000) farms around the world in order
to spread goodwill between farmers and their cows. For simplicity, the
world will be represented as a two-dimensional plane, where each farm is
located at a pair of integer coordinates (x,y), each having a value in
the range -10,000 … 10,000. No two farms share the same pair of
coordinates.

Even though Bessie travels directly in a straight line between pairs of
farms, the distance between some farms can be quite large, so she wants to
bring a suitcase full of hay with her so she has enough food to eat on
each leg of her journey. Since Bessie refills her suitcase at every farm
she visits, she wants to determine the maximum possible distance she
might need to travel so she knows the size of suitcase she must bring.
Help Bessie by computing the maximum distance among all pairs of farms.

PROBLEM NAME: msworld

INPUT FORMAT:

* Line 1: A single integer, N

* Lines 2..N+1: Two space-separated integers x and y specifying
coordinate of each farm

SAMPLE INPUT (file msworld.in):

4
0 0
0 1
1 1
1 0

OUTPUT FORMAT:

* Line 1: A single integer that is the squared distance between the
pair of farms that are farthest apart from each other.

SAMPLE OUTPUT (file msworld.out):

2

OUTPUT DETAILS:

Farm 1 (0, 0) and farm 3 (1, 1) have the longest distance (square root of
2)

**********************************************************************

USACO FALL 2003题解

为了热身NOIP做了这个比赛。。
Fall 2003
水平有限。。我是沙茶。。
Problem 1:
有限制的背包问题。。
首先把S、B都大于0的选了。。
首先把S、B都小于或等于0的扔掉。。
那么所剩的就是一项正一项负了。。
按照其中的一项从大到小排序。。必然是如下形式。。
S B
+ -
+ -
。。。以(S的正负性为划分线)
-  +
-  +
。。。
设S已经有了HaveS(来源于先前已经选的东西。。肯定为正。。)
对上下两个分别运行背包。。求出上下两个容量各个选择容量时B和的最大值。。
为了方便把下面的那个背包价格S值全部取反。。这样当上面背包S为和X时。。下面的最多为X+HaveS个。。
那么可以枚举上面的背包的S值。并用个变量记录下面的最小值。。若B和的最大值加上原来先前选的B的和大于0的话。。
用于更新最优解。。
P.S实际上直接暴力背包也可以。。但我估计要TLE。。进行一些优化之后可以快N多。。
几个小优化。。
首先若上面S的和为SumS,则不需要考虑下面SumS+HaveS以后的状态。。因为根本不会用到。。
那么上面的的和自然要小。。
故在下面比上面短的时候可以交换上下两个。。(也就是交换S和B的位置)
众所周知DP需要一个序
直接的暴力DP没有考虑到题目的特性而运用了盲目的序。。
而结合题目的特性可以得出更好的序从而更高效的算法俄。。
Problem 2:
好难阿。。应该要用到分治吧。。我不会阿。。教教我阿。。
Promblem 3:
比较水的问题。。首先很明显要求出强连同分量。。然后转化成DAG。。
题目就是求一个节点到其他所有节点都有路径。。
因为没有环。。故一个节点如果有入度那么一定不能到达射向他的那个顶点。。不然就有环了。。
故只有没有入度的节点可能满足条件。。
如果有两个或以上的话。。那么这两个节点必不能互达。。故无解
如果有一个的话。。那个节点就是答案了。。
Problem 4:
OI中数据范围不一样的题目真不是一道题目阿。。
题目就是求N个点中最长的两点间距离。。假如N<1000的话直接暴力就OK了。。可惜N<50000
先求出凸包。。那么最长距离一定在凸包上。。
尽管平均意义上凸包上的点为N的三次方根的数量级。。那么直接枚举凸包上的点对就是N的三分之二次方。。
可惜那是平均意义上的。。很容易就可以构造出所有点都在凸包上的BT数据。。显然不行。。
实际上求凸包上的最远点利用对重点可以做到O(N)但我不会。。
我发现凸包上的点的距离是有单峰性的。。故可以用ternary查找其最值。。是logn的。。
加上排序。。还是NlogN。。勉强过吧。。

SPOJ 726

都说叫分段HASH。。
我觉得还是有点块状数组的感觉。。
用stl写平衡数很方便不过还是块状数组爽。。
可以是负数的阿。。好贱。。。
Code。。
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=1000001,maxv=maxn*2,maxsize=1000,maxL=maxv/maxsize+10;
int C[maxv]={0};
int D[maxL]={0};
int n,Blocks;
void insert(int n)
{
C[n]++;
D[n/maxsize]++;
}
void del(int n)
{
C[n]–;
D[n/maxsize]–;
}
int getMin()
{
int i,j;
for(i=0;i<maxL;i++)
if(D[i]) break;
for(j=i*maxsize;;j++)
if(C[j]) break;
return j;
}
int getMax()
{
int i,j;
for(i=maxL-1;i>=0;i–)
if(D[i]) break;
for(j=(i+1)*maxsize-1;;j–)
if(C[j]) break;
return j;
}
int main()
{
cin>>n;int k,t;
long long ans=0;
while(n–)
{
scanf("%d",&k);
while(k–)
scanf("%d",&t),insert(t+maxn);
int Max=getMax(),Min=getMin();
ans+=Max-Min;
del(Max);del(Min);
}
cout<<ans<<endl;
}

sgu 347-357 部分(2)

356。。。
实际上求的就是N的排列中多少个排列只有K个不在位置上。。
那么答案就是C(N,K)*D(N-K)。。D是错排。。错排不知道者可以google之。。
但是高精十分BT。。实际上我怎么会没时间写模拟题呢?都是栽在这题上了。。555
不过总算是在比赛结束前过了。。
由于输出居然是要用不可约分数。。莫非要写一个高精度欧几里得算法吗?天阿。。
如果你真去写那你就傻了。。。
答案是D(n-k)/((n-k)!(k)!)
换句话说公约数的素因子《=100。。。
那么一个个化就OK了。。
不过程序还是很长。。好羡慕JAVA阿。。自带高精度运算功能的。。
#include<iostream>
#include<cstring>
#define REP(i,n) for(int i=0;i<n;i++)
using namespace std;
const int maxn=110;
int Prime[]=
{2,3,5,7,11,
13,17,19,23,29
,31,37,41,43,47
,53,59,61,67,71
,73,79,83,89,97};
const int ps=25;
int N,K;
struct Num
{
int P;
Num(){memset(P,0,sizeof(P));}
void mult(int a)
{
for(int i=0;i<ps;i++)
{
if(a==1) break;
while(a%Prime[i]==0)
a/=Prime[i],P[i]++;
}
}
void divide(int a)
{
for(int i=0;i<ps;i++)
{
if(a==1) break;
while(a%Prime[i]==0)
a/=Prime[i],P[i]–;
}
}
};
const int maxlen=200;
struct BigNum
{
int Q[maxlen],last;
BigNum(int x=0)
{memset(Q,0,sizeof(Q));Q[0]=x;last=0;}
int operator[](int v) const
{return Q[v];}
int& operator[](int v)
{return Q[v];}
BigNum operator+(const BigNum&x)
{
BigNum now;now.last=max(last,x.last);
int d=0;
for(int i=0;i<=now.last;i++)
{
d+=Q[i]+x[i];
now[i]=d%10;
d/=10;
}
while(d)
{
now[++now.last]=d%10;
d/=10;
}
return now;
}
void operator*=(int x)
{
int d=0;
for(int i=0;i<=last;i++)
{
d+=Q[i]*x;
Q[i]=d%10;
d/=10;
}
while(d>0)
{
Q[++last]=d%10;
d/=10;
}
}
BigNum operator*(const BigNum&x)
{
BigNum now;now.last=x.last+last;
memset(now.Q,0,sizeof(Q));
for(int i=0;i<=last;i++)
for(int j=0;j<=x.last;j++)
now[i+j]+=Q[i]*x[j];
int d=0;
for(int i=0;i<=now.last;i++)
{
d+=now[i];
now[i]=d%10;
d/=10;
}
while(d)
{
now[++now.last]=d%10;
d/=10;
}
}
int Mod(int x)
{
int d=0;
for(int i=last;i>=0;i–)
{
d*=10;
d+=Q[i];
d%=x;
}
return d;
}
void Divide(int x)
{
int rest=0;
for(int i=last;i>=0;i–)
{
rest=rest*10+Q[i];
Q[i]=rest/x;
rest%=x;
}
while(Q[last]==0)
last–;
}
void operator=(const BigNum&x)
{
last=x.last;
memmove(Q,x.Q,sizeof(Q));
}
void show()
{
for(int i=last;i>=0;i–)
cout<<Q[i];
}
};
BigNum Get(Num x)
{
BigNum now(1);
for(int i=0;i<ps;i++)
{
for(int j=0;j<x.P[i];j++)
now*=Prime[i];
}
return now;
}
BigNum D[maxn];
void CalD(int n)
{
D[0][0]=1;D[1][0]=0;
for(int i=2;i<=n;i++)
{
D[i]=D[i-1]+D[i-2];
D[i]*=(i-1);
}
}
Num C;
int main()
{
cin>>K>>N;
if(N-K==1)
{
cout<<0<<endl;
return 0;
}
CalD(N-K);
for(int i=1;i<=K;i++)
C.mult(i);
for(int i=1;i<=N-K;i++)
C.mult(i);
BigNum left,right;
left=D[N-K];
for(int i=0;i<ps;i++)
{
while(left.Mod(Prime[i])==0&&C.P[i]>0)
left.Divide(Prime[i]),C.P[i]–;
}
right=Get(C);
left.show();cout<<"/";right.show();
}
357。。。好无聊的水题阿。。要是能跳明显一开始就跳。。
然后枚举每个开始UP or DOWN的点算答案。。。
Code。。。
#include<iostream>
#define REP(i,n) for(int i=0;i<n;i++)
using namespace std;
const int inf=~0U>>2;
bool Digit[10]={0};
bool UP,DOWN,FLY;
int dist[100],s,t;
void init()
{
cin>>Digit[1]>>Digit[2]>>Digit[3]>>UP>>
Digit[4]>>Digit[5]>>Digit[6]>>DOWN>>
Digit[7]>>Digit[8]>>Digit[9]>>FLY>>Digit[0];
}
void renew(int&x,int c)
{
x=min(x,c);
}
void Fly()
{
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
if(Digit[i]&&Digit[j])
renew(dist[i*10+j],3);
}
void Go(int j)
{
int c=dist[j];
if(UP)
renew(dist[(j+1)%100],c+1);
if(DOWN)
renew(dist[(j+99)%100],c+1);
}
int main()
{
init();cin>>s>>t;
REP(i,100) dist[i]=inf;
dist[s]=0;
if(FLY)
Fly();
for(int i=0;i<10;i++)
if(Digit[i])
renew(dist[i],1);
int ans=dist[t];
for(int i=0;i<100;i++)
if(dist[i]!=inf)
{
if(UP)
renew(ans,(t-i+100)%100+dist[i]);
if(DOWN)
renew(ans,(i-t+100)%100+dist[i]);
}
if(ans==inf)
cout<<-1<<endl;
else
cout<<ans<<endl;
}

sgu 347-357 部分(1)


参加了虚拟比赛11道只做了5道。。SB阿。。
346和353都是模拟的题目。。懒得做了。。
347。。看代码吧。。
Code。。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=100+10;
string A[maxn];
bool cmp(const string&A,const string&B)
{
return (A+B)<(B+A);
}
int main()
{
int N;cin>>N;
for(int i=0;i<N;i++)
cin>>A[i];
sort(A,A+N,cmp);
for(int i=0;i<N;i++)
cout<<A[i];
cout<<endl;
}
350。。
有点意思的题目。。
首先如果有一个解。。那么把这些数全部xor上一个数的话。。还是一个解。。
因为(a xor x) xor (b xor x)=(a xor b) xor (x xor x)= a xor b xor 0= a xor b。。。
所以就当里面有一个0好了。。
然后特判掉M=1的情况。。
那么注意到。。如果B中有两个数A和B。。A xor B=另一个数C。。
那么A和B必然有公共的元素。。
那么就很简单了。。找两个有公共元素的B中的数i,j。。强行将它们的公共元素设为0。。
那么现在就有3个数了0,i,j。。
那么只要找其他的有0的元素就可以求出一个解了。。怎么求找呢?
如果B中数x不是i xor j。。又跟i和j都有公共元素。。那么这个公共元素只能是0了。。那么这个数就属于解了。。。
就这样找数。。。
#include<iostream>

#define REP(i,n) for(int i=0;i<n;i++)
using namespace std;
const int maxn=100;
int M,B[maxn];
bool HaveCommon(int i,int j,int&k)
{
int now=B[i]^B[j];
for(k=0;k<M;k++)
if(B[k]==now)
return true;
return false;
}
int main()
{
cin>>M;
REP(i,M) cin>>B[i];
if(M==1)
{
cout<<(B[0]-1)<<" "<<(B[0]^(B[0]-1))<<endl;
return 0;
}
int ans[maxn];ans[0]=0;int i,j,k;
bool mark[maxn]={0};
for(i=0;i<M;i++)
for(j=i+1;j<M;j++)
if(HaveCommon(i,j,k))
{
ans[1]=B[i],ans[2]=B[j],mark[i]=mark[j]=mark[k]=true;
goto out;
}
out:
int cnt=3,t;
for(int o=0;o<M;o++) if(!mark[o])
if(HaveCommon(o,i,t)&&HaveCommon(o,j,t))
ans[cnt++]=B[o];
cout<<ans[0];
for(int i=1;i<cnt;i++)
cout<<" "<<ans[i];
cout<<endl;
}355。。。
构造题。。很明显答案是logN+1…
染色的话只要染成素因数个数就OK了。。
#include<iostream>
using namespace std;
int num(int p)
{
int cnt=0;
while(p%2==0)
{cnt++;p/=2;}
while(p%3==0)
{cnt++;p/=3;}
for(int i=5,j=25,k=4;j<=p;i+=(k=6-k),j+=(i*2-k)*k)
{
while(p%i==0)
{cnt++;p/=i;}
}
if(p!=1)
cnt+=2;
else
cnt+=1;
return cnt;
}
int main()
{
int N,x,cnt=0;cin>>N;x=1;
while(x<=N){cnt++;x*=2;}
cout<<cnt<<endl;
for(int i=1;i<N;i++)
cout<<num(i)<<" ";
cout<<num(N)<<endl;
}

SPOJ 2185

http://www.spoj.pl/problems/MUSIC/
USACO不知那年那月的月赛题。。。
看上去很BT。。但如果看一下部分和的话。。
会发现搞那么多也就是交换Sx-1于Sy。。
要让条件满足。。必须要把部分和顺序排序。。并且S1>0以及没有相同的部分和。。
那么最小交换数就是n-轮换数。。很好求。。
Code。。。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
const int maxn=100000;
using namespace std;
int S[maxn],P[maxn],n;
bool cmp(const int&x,const int&y)
{
return S[x]<S[y];
}
void Judge()
{
if(S[P[0]]<=0)
cout<<-1<<endl,exit(0);
for(int i=1;i<n;i++)
if(S[P[i]]==S[P[i-1]])
cout<<-1<<endl,exit(0);
}
void init()
{
scanf("%d",&n);
scanf("%d",S);P[0]=0;
for(int i=1;i<n;i++)
{
scanf("%d",S+i);
S[i]+=S[i-1];
P[i]=i;
}
sort(P,P+n,cmp);
Judge();
}
void solve()
{
bool mark[maxn]={0};int ans=n;
for(int i=0;i<n;i++) if(!mark[i])
{
int t=i;
while(!mark[t])
mark[t]=true,t=P[t];
ans–;
}
cout<<ans<<endl;
}
int main()
{
init();
solve();
}

SPOJ 2747

http://www.spoj.pl/problems/SUMSUMS/
最近在做USACO以前的月赛题备战NOIP哎。。。
这道是2007 CHN的。。
琢磨一下可以发现对于每个人来说。。S是所有Ci的总和
任何次数下他的值都是A*S+B*Ci。。且这个A和B只要给定了次数,跟i是无关的。。
可以导出A和B的递推式:
A’=(n-1)*A+B;
B’=-B;
。。但是T太大了。。只好用矩阵乘法加速了。。。
矩阵为
n-1 1
0    -1
Code。。。
#include<iostream>
#include<cstring>
#include<cstdio>
#define REP(i,n) for(int i=0;i<n;i++)
using namespace std;
typedef long long Board[2][2];
const int maxn=50000;
const long long Mod=98765431;
int N;
long long T;
int C[maxn];
struct Matrix
{
Board own;       
Matrix(){memset(own,0,sizeof(own));}
Matrix operator*(const Matrix&x)
{
Matrix now;
REP(i,2) REP(j,2)
{
REP(k,2)now.own[i][j]+=(own[i][k]*x.own[k][j])%Mod;
now.own[i][j]%=Mod;if(now.own[i][j]<0) now.own[i][j]+=Mod;
}
return now;
}
long long* cal(int A[])
{
long long* ans=new long long[2];
ans[0]=ans[1]=0;
REP(i,2) REP(j,2)
ans[i]+=own[i][j]*A[j];
return ans;
}
void operator=(const Matrix&x)
{
memmove(own,x.own,sizeof(own));
}
}ans,orig;
Matrix power(long long t)
{
if(t==1)   
{
return orig;
}
Matrix now;   
now=power(t/2);
now=now*now;
if(t%2==1)
now=now*orig;
return now;
}
int main()
{
cin>>N>>T;int S=0;
REP(i,N) {scanf("%d",C+i);S+=C[i];S%=Mod;}
orig.own[0][0]=N-1;orig.own[0][1]=1;
orig.own[1][0]=0;orig.own[1][1]=-1;
ans=power(T);
int A[2]={0,1};
long long*get=ans.cal(A);
REP(i,N)
{
long long t=get[0]*S+get[1]*C[i];
t%=Mod;
printf("%lldn",t);
}
}

sgu 395

这道题我居然想出来了。。只有11个人AC哎。。好激动。。
一下就看出可以用有上下界的最小费用可行流。。
就是对增加的处理有些BT。。
每个人分开讨论
如果把来了看成+号,走了看成-号。。那么对于相邻的两个。。
1++。。中间肯定要加个-。。
2+-。。可以不加。。也可以在中间加-+。。
3–。。中间肯定要加个+。。
当然可以狂加+-+-+-之类的。。但是可以看成一个新人来简化问题。。
于是分别处理以上三种情况。。具体太繁琐。。简单说一下。。
1和3好处理。。加个顶点就OK了。。
2很BT。。要加2个顶点。。我想了半天突然明悟了。。。
新人的话只需要用容量无限费用为1的边就可以了。。
不过我不会写有上下界的最小费用可行流。。无语。。。
去学学再去AC这题吧。。。
N不大时间应该够。。
P.S似乎运用了网络流中配“零件”的思想。。配“零件”。。真好玩。。。

sgu 327

想了半天。。发现居然是一个最短哈密顿路的模型(注意不是环。。)
首先把被包含的扔掉。。那么建立N个顶点代表字符串。。
两点的距离就是这两个字符串接起来增加的字符数*2。。
图是完全的。。边是有向的。。
那么用集合DP就可以搞定了。。先要枚举开始的顶点。。
复杂度就是(N^3*2^N)。。也能过。。
。。正在写。。
写了半天。。弄了个半成品。。路径实在不想写了。。只能算个答案
注意一下。。连接的话有4种方式(T表示正的放。。R表示反着放)
T<- T R -> R
R<- R T -> T
T<- R T -> R
R<- T R -> T
。。。BT。。。
这么搞的话再构造方案岂不是要死人阿。。
Code。。
#include<string>
#include<iostream>
#include<queue>
#define REP(i,n) for(int i=0;i<n;i++)
using namespace std;
const int maxn=14,inf=~0U>>1;
int N=0,ans=~0U>>1;
string B[maxn];
int dist[maxn][maxn];
string Reverse(string tmp)
{
for(int s=0,t=tmp.length()-1;s<t;s++,t–) swap(tmp[s],tmp[t]);
return tmp;
}
int maxcommon(const string&x,const string&y)
{
int ans=0;
for(int i=1;i<=min(x.length(),y.length());i++)
if(x.substr(x.length()-i,i)==y.substr(0,i))
ans=i;
return ans;
}
void init()
{
int cnt;cin>>cnt;
string A[maxn];
for(int i=0;i<cnt;i++)
cin>>A[i];
for(int i=0;i<cnt;i++)
{
bool find=false;
for(int j=0;j<cnt;j++) if(j!=i)
if(A[j].find(A[i])!=string::npos)
{find=true;break;}
if(!find)
B[N++]=A[i];
}
for(int i=0;i<N;i++)
for(int j=0;j<N;j++) if(i!=j)
{
int a=B[j].length()*2-maxcommon(B[j],B[i])*2;
int b=B[j].length()*2-maxcommon(Reverse(B[j]),B[i])*2;
int c=B[j].length()*2-maxcommon(B[j],Reverse(B[i]))*2;
int d=B[j].length()*2-maxcommon(Reverse(B[j]),Reverse(B[i])))*2;
dist[i][j]=min(min(min(a,b),c),d);
}
}
int DP[1<<maxn][maxn];
struct node
{
int state,pos;
node(int s,int p):state(s),pos(p){}
};
void start(int i)
{
string tmp=Reverse(B[i]);
REP(j,1<<N) REP(k,N) DP[j][k]=inf;
DP[1<<i][i]=B[i].length()*2-maxcommon(B[i],tmp);
queue<node> Q;
Q.push(node(1<<i,i));
while(Q.size())
{
node cur=Q.front();Q.pop();
int s=cur.state,p=cur.pos;
for(int j=0;j<N;j++) if(s^(1<<j))
{
int ns=s^(1<<j),get=DP[s][p]+dist[p][j];
if(DP[ns][j]>get)
DP[ns][j]=get,Q.push(node(ns,j));
}
}
REP(j,N) if(DP[(1<<N)-1][j]<ans)
ans=DP[(1<<N)-1][j];
}
void solve()
{
for(int i=0;i<N;i++)
start(i);
cout<<ans<<endl;
}
int main()
{
init();
solve();
}

SPOJ 297

。。。传送门。。。
http://www.spoj.pl/problems/AGGRCOW/。。。
二分+贪心麻。。很明显如果知道答案越往钱放越好嘛。。。
代码太短了。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100000;int N,C,X[maxn];
bool Can(int limit)
{
int old=0,now=1;
for(int i=1;i<C;i++)
{
while(X[now]-X[old]<limit&&now<N)
now++;
if(now>=N)
return false;
old=now;now++;
}
return true;
}
void solve();
int main()
{
int t;cin>>t;
while(t–)
{       
solve();
}
}
void solve()
{
cin>>N>>C;
for(int i=0;i<N;i++)
scanf("%d",X+i);
sort(X,X+N);
int l=1,r=X[N-1];
while(l+1<r)
{
int mid=(l+r)/2;
if(Can(mid))
l=mid;
else
r=mid;
}
cout<<l<<endl;
}