[FOJ1902 Graduate]动态规划

【题目大意】
给出N个人,他们高度各不相同,让他们站两排,满足:
1、同一个位置的人中,前面的比后面的矮。
2、最终没有一排是空的,而且后面那排的人数<=前面那排。
3、如果i站在j的左边,那么i比j矮。
问有多少种方案。
结果mod 20100501
【算法分析】
dp
F[i][j]表示前面那排排了i个人,后面那排排了j个人。
那么方程就是F[i][j]=F[i-1][j]+F[i,j-1]。(i>=j && i+j<=n)
初始F[0][0]=1。
【时间复杂度】O(n^2)
【CODE】
#include #include #include int a[105];
int f[105][105];

void init(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
}

void dp(){
memset(f,0,sizeof(f));
f[0][0]=1;
int i,j;
for (i=0;i<=n;i++)
for (j=0;i+j<=n && j<=i;j++)
if (i+j>0){
if (i) f[i][j]+=f[i-1][j];
if (j) f[i][j]+=f[i][j-1];
f[i][j]%=20100501;
}
int ans=0;
for (i=1;i<=n/2;i++){
ans+=f[n-i][i];
ans%=20100501;
}
printf("%dn",ans);
}

int main(){
int Tc;
scanf("%d",&Tc);
for (int i=1;i<=Tc;i++){
printf("Case #%d: ",i);
init();
dp();
}
}

[FOJ1903 Regular Brackets]贪心、无权修改括号序列、O(n)

【题目大意】
给定一个括号序列,让你修改最少的次数,使之成为一个合法的括号序列。
输出这个修改次数,并输出最终字典序最小的修改后的结果。
【算法分析】
Orz。。。这类题是我最不擅长的。。。应该说直觉不够好么。。。
下面引用lcc大牛的做法:

先从左向右扫 一旦扫到一个失配的’)’就将左边第一个’)’强转‘(’ 然后反过来做一遍 这样得到的一定是最小转化而且是最小字典序

一开始我也想到个类似的,然后我居然去想,这第一个’)’会不会不能转呢。。。
= =,晕,在正向枚举的时候,stack本来就可以超过0。本就不需要考虑失配。
太SB了。。。然后就这样。
【复杂度】O(n)
【CODE】
#include #include #include const int N=1000005;
int Tc,n,ans;
int Q[N];
char S[N];

void solve1(){
int stack=0,h=1,t=0,i;
for (i=1;i<=n;i++)
if (S[i]=='(‘) stack++;
else{
Q[++t]=i;
if (!stack){
S[Q[h++]]='(‘;
ans++;
stack++;
}
else stack–;
}
}

void solve2(){
int stack=0,h=1,t=0,i;
for (i=n;i>=1;i–)
if (S[i]==’)’) stack++;
else{
Q[++t]=i;
if (!stack){
S[Q[h++]]=’)’;
ans++;
stack++;
}
else stack–;
}
}

int main(){
scanf("%d",&Tc);
for (int i=1;i<=Tc;i++){
scanf("%s",S+1);
n=strlen(S+1);
ans=0;
solve1();
solve2();
printf("Case #%d: %dn",i,ans);
puts(S+1);
}
}

[FOJ1898 Cows Arrangement]超Orz的差分约束系统~

【题目大意】
有一个数组d[1..n]
d[1]=0,d[i]然后给出一些限制,
第一种:x,y,w,d[y]-d[x]<=w(数据保证x第二种:x,y,w,d[y]-d[x]>=w(数据保证x一个d[i]=k满足条件当且仅当存在一组d[1..n]满足限制,而且d[i]=k。
【算法分析】
完全没想到。。。一开始写了个二分+差分判可行了。。。完全超时到天荒地老。。。
后来看正解。
非常Orz。就是按题目的这些不等式建图。
第一次,按最短路来建图,d[1]设为0,然后其他全设为无穷大。跑一遍最短路的spfa。
第二次,按最长路来建图,d[1]设为0,然后其他也全设为0。跑一遍最长路的spfa。

然后、然后、很Orz地他就解决了。。。

最短路跑出的是最大值。
最长路跑出的是最小值。

为什么呢?
因为他都是按照那个不等式最贴边的方式解得。
所以最短路就是刚好<=那个上界。
而最长路则是刚好>=那个下界。

So,Orz。。。。
【CODE】
#include #include #include #include #include using namespace std;
const int N=5005;
const int INF=100000000;
int n;
int L[N],R[N],d[N],Q[N],v[N],Inn[N];
bool flag;
struct edge{int x,y,w;edge *next;};
struct Link_t{
edge sp[N],*ls[N];
int e;
void init(){
e=0;
for (int i=1;i<=n;i++) ls[i]=NULL;
}

void addedge(int x,int y,int w){
e++;
sp[e].x=x; sp[e].y=y; sp[e].w=w;
sp[e].next=ls[x]; ls[x]=&sp[e];
}
}Hate,Love,G;

void input(){
int ml,mh,i,x,y,w;
scanf("%d%d%d",&n,&ml,&mh);
Hate.init();
Love.init();
for (i=1;i<=ml;i++){
scanf("%d%d%d",&x,&y,&w);
Love.addedge(x,y,w);
}
for (i=1;i<=mh;i++){
scanf("%d%d%d",&x,&y,&w);
Hate.addedge(x,y,w);
}
}

void build1(){
G.init();
int i;
for (i=1;i<=Love.e;i++){
edge *t=&Love.sp[i];
G.addedge(t->x,t->y,t->w);
}
for (i=1;i<=Hate.e;i++){
edge *t=&Hate.sp[i];
G.addedge(t->y,t->x,-t->w);
}
for (i=1;i G.addedge(i+1,i,-1);
G.addedge(1,n,INF);
}

void spfa1(){
for (int i=1;i<=n;i++){
Inn[i]=0;
v[i]=0;
d[i]=INF+22;
}
int head=0,tail=1;
d[1]=0; Q[1]=1; v[1]=1;
while (head!=tail){
head++; if (head>=N) head=0;
for (edge *t=G.ls[Q[head]];t;t=t->next)
if (d[t->x]+t->w d[t->y]=d[t->x]+t->w;
if (d[t->y]<0){
flag=false;
return;
}
if (!v[t->y]){
v[t->y]=1;
tail++; if (tail>=N) tail=0;
Q[tail]=t->y;
Inn[t->y]++;
if (Inn[t->y]>n){
flag=false;
return;
}
}
}
v[Q[head]]=0;
}
}

void build2(){
G.init();
int i;
for (i=1;i<=Love.e;i++){
edge *t=&Love.sp[i];
G.addedge(t->y,t->x,-t->w);
}
for (i=1;i<=Hate.e;i++){
edge *t=&Hate.sp[i];
G.addedge(t->x,t->y,t->w);
}
for (i=1;i G.addedge(i,i+1,1);
G.addedge(n,1,-INF);
}

void spfa2(){
for (int i=1;i<=n;i++){
v[i]=0;
d[i]=0;
}
int head=0,tail=1;
d[1]=0; Q[1]=1; v[1]=1;
while (head!=tail){
head++; if (head>=N) head=0;
for (edge *t=G.ls[Q[head]];t;t=t->next)
if (d[t->x]+t->w>d[t->y]){
d[t->y]=d[t->x]+t->w;
if (!v[t->y]){
v[t->y]=1;
tail++; if (tail>=N) tail=0;
Q[tail]=t->y;
}
}
v[Q[head]]=0;
}
}

void output(){
puts("Exist!");
for (int i=1;i<=n;i++)
printf("%d %dn",L[i],R[i]);
}

int main(){
int Tc;
scanf("%d",&Tc);
for (int i=1;i<=Tc;i++){
printf("Case #%d: ",i);
input();
flag=true;
build1();
spfa1();
if (!flag){
puts("Not Exist!");
continue;
}
for (int j=1;j<=n;j++) R[j]=d[j];
build2();
spfa2();
for (int j=1;j<=n;j++) L[j]=d[j];
output();
}
}

[FOJ1901 Period II]拓展KMP算法

【题目大意】
给出一个串,让你求出所有满足S[1..n-k+1]=S[k..n]的k-1的值。
【算法分析】
一看到题目。。。这不就是拓展KMP的数组直接判断么。。。
于是直接写了拓展KMP。
虽然KMP也可以。
这个当做是我的拓展KMP例题好了。
【CODE】
#include #include #include #define max(x,y) ((x)>(y)?(x):(y))
const int N=1000005;
int n,ans;
int b[N],ansl[N];
char S[N];

void exkmp(){
int i,j,k,a,p;
b[1]=n;
for (i=2;i<=n && S[i]==S[i-1];i++);
i–;
b[2]=i-2+1;
p=i;
a=2;

for (i=3;i<=n;i++)
if (b[i-a+1]+i-1 b[i]=b[i-a+1];
else{
k=max(p+1-i,0);
while (i+k<=n && S[i+k]==S[k+1]) k++;
b[i]=k;
a=i;
p=i+b[i]-1;
}

ans=0;
for (i=2;i<=n;i++)
if (b[i]==n-i+1) ansl[++ans]=i-1;
ansl[++ans]=n;
printf("%dn",ans);
for (i=1;i<=ans;i++){
printf("%d",ansl[i]);
if (i==ans) printf("n");
else printf(" ");
}
}

int main(){
int Tc;
scanf("%d",&Tc);
for (int i=1;i<=Tc;i++){
printf("Case #%d: ",i);
scanf("%s",S+1);
n=strlen(S+1);
exkmp();
}
}

[COCI 2009/2010 – Constest #7 RESTORAN]AC、随机算法、非完美

【题外话】
这题之前写过一个题解了。
地址是:http://hi.baidu.com/edwardmj/blog/item/592566ad221c3ac07cd92a87.html
之前的算法没有AC。然后看了到处转了一转,又围观了神牛的代码。
各种构造法弄到头晕。。。
Orz。。。还是没看懂。然后我写起了当时扬言要写的随机算法。
【算法分析】
同样是当作树来DFS。
DFS时就判断当前点有没有1这种颜色。没有的话染1。
再判断有没有2这种颜色。没有的话染2。
否则得话,染颜色rand()%2+1。
然后出来以后还没染得,就看两边缺啥就染啥。
如果无解的话,重新染。直到无解10次那就真无解。
否则输出。
【评测结果】
Test # Score Time Memory Result 1 6.5 0.00s 6652 kB Correct! 2 6.5 0.00s 6652 kB Correct! 3 6.5 0.00s 6652 kB Correct! 4 6.5 0.00s 6652 kB Correct! 5 52.0 0.00s 6652 kB Correct! 0.00s 6652 kB Correct! 0.00s 6652 kB Correct! 0.00s 6652 kB Correct! 0.00s 6652 kB Correct! 0.01s 6652 kB Correct! 0.00s 6652 kB Correct! 0.00s 6652 kB Correct! 6 52.0 0.50s 9696 kB Correct! 0.09s 6652 kB Correct! 0.00s 6652 kB Correct! 0.13s 9696 kB Correct! 0.12s 7608 kB Correct! 0.19s 8288 kB Correct! 0.11s 7416 kB Correct! 0.12s 7944 kB Correct! 【CODE】
#include #include #include const int N=105555;
struct edge{int x,y,c,next,op;}g[N*2];
int n,e,times=0;
int ls[N],du[N],c1[N],c2[N];
bool v[N];

inline void addedge(int x,int y){
g[++e].x=x; g[e].y=y; g[e].next=ls[x]; ls[x]=e; g[e].op=e+1; g[e].c=0;
g[++e].x=y; g[e].y=x; g[e].next=ls[y]; ls[y]=e; g[e].op=e-1; g[e].c=0;
}

void init(){
e=0;
memset(ls,0,sizeof(ls));
memset(du,0,sizeof(du));
int i,x,y,m;
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++){
scanf("%d%d",&x,&y);
addedge(x,y);
du[x]++; du[y]++;
}
}

void draw(int t,int co){
g[t].c=co; g[g[t].op].c=co;
if (co==1){c1[g[t].x]++; c1[g[t].y]++;}
else{c2[g[t].x]++; c2[g[t].y]++;}
}

void dfs(int p){
for (int t=ls[p];t;t=g[t].next)
if (!v[g[t].y]){
v[g[t].y]=true;
if (!c1[p]) draw(t,1);
else if (!c2[p]) draw(t,2);
else draw(t,rand()%2+1);
dfs(g[t].y);
}
}

void work(){
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
memset(v,false,sizeof(v));
for (int i=1;i<=e;i++) g[i].c=0;
for (int i=1;i<=n;i++)
if (!v[i]){
v[i]=true;
dfs(i);
}
for (int t=1;t<=e;t++)
if (!g[t].c)
if (!c1[g[t].x] && du[g[t].x]>1 || !c1[g[t].y] && du[g[t].y]>1) draw(t,1);
else draw(t,2);
bool flag=true;
for (int i=1;i<=n;i++)
if (du[i]>1 && (!c1[i] || !c2[i])) flag=false;
if (!flag){
if (times<10){
times++;
work();
return;
}
printf("0n");
}
else
for (int i=1;i printf("%dn",g[i].c);
}

int main(){
srand(19930505);
// freopen("input2.txt","r",stdin);
// freopen("output.txt","w",stdout);
init();
work();
}