[APIO2010 commando]斜率优化1D/1D方程、动态规划

【题目地址】http://www.apio.olympiad.org/
【算法分析】
易得方程F[i]=F[j]+g(Si-Sj)  g为那个二次函数。
然后列不等式F[j]+g(Si-Sj)变形得(F[j]-F[k]+a*(Sum[j]*Sum[j]-Sum[k]*Sum[k])+b*(Sum[k]-Sum[j])) / ((Sum[j]-Sum[k])*a*2) <=Si。
然后这就是经典的斜率优化dp。
【CODE】
#include #include #include #include using namespace std;
typedef long long lld;
const int N=1000005;
const lld INF=(lld)(1)<<60;
int n,a,b,c;
int xl[N],Q[N];
lld Sum[N],F[N];
char ch;
bool fu;

void Read(int &x){
ch=getchar();
while (!(ch>=’0′ && ch<='9' || ch=='-')) ch=getchar();
x=0;
fu=false;
if (ch==’-‘){
fu=true;
ch=getchar();
}
while (ch>=’0′ && ch<='9'){
x=x*10+ch-‘0’;
ch=getchar();
}
if (fu) x=-x;
}

void input(){
Read(n);
Read(a); Read(b); Read(c);
for (int i=1;i<=n;i++)
Read(xl[i]);
Sum[0]=0;
for (int i=1;i<=n;i++)
Sum[i]=Sum[i-1]+xl[i];
}

inline lld g(lld x){return x*x*a+x*b+c;}
inline lld pos(int j,int k){
return (F[j]-F[k]+a*(Sum[j]*Sum[j]-Sum[k]*Sum[k])+b*(Sum[k]-Sum[j]))/
((Sum[j]-Sum[k])*a);
}

void work(){
int i,j,h,t;
h=t=1; Q[1]=0;
F[0]=0;
for (i=1;i<=n;i++) F[i]=-INF;
for (i=1;i<=n;i++){
while (h F[i]=F[Q[h]]+g(Sum[i]-Sum[Q[h]]);
while (h t++;
Q[t]=i;
}
cout << F[n] << endl;
}

int main(){
freopen("commando.in","r",stdin);
freopen("commando.out","w",stdout);
input();
work();
}

[Elite 2010 U S Open Competition]求过原点的三角形数目、极角排序、维护

【题目大意】
给定N个二维平面上的点。
问他们取3个出来,过原点的三角形有多少个。
【算法分析】
先极角排序。
然后维护一个最长区间,使得区间中任意一个点对满足向量(O, i)和向量(O, j)的夹角【其它】
APIO最后一题的本质模型。
【CODE】
/*
ID:jie22221
TASK:tricount
LANG:C++
*/

#include #include #include #include using namespace std;
typedef long long lld;
const int N=100005;
int n;
struct Point{int x,y;}a[N];

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

int get_xx(Point p){
if (p.x>=0 && p.y>0) return 1;
if (p.x>0 && p.y<=0) return 2;
if (p.x<=0 && p.y<0) return 3;
return 4;
}

int cj(Point p0,Point p1,Point p2){
lld res=(lld)(p1.x-p0.x)*(lld)(p2.y-p0.y)-(lld)(p1.y-p0.y)*(lld)(p2.x-p0.x);
if (res<0) return -1;
if (res==0) return 0;
return 1;
}

int cmp(const void *X,const void *Y){
Point x=*((Point*)X),y=*((Point*)Y);
int xx1=get_xx(x),xx2=get_xx(y);
if (xx1!=xx2) return xx1-xx2;
return cj(a[0],x,y);
}

void solve(){
lld ans=(lld)(n)*(n-1)*(n-2)/6,total;
int i,j=1;
for (i=1;i<=n;i++){
if (i==j) j=j%n+1;
while (i!=j%n+1 && cj(a[0],a[i],a[j%n+1])<0) j=j%n+1;
if (j else total=j-i;
ans-=total*(total-1)/2;
}
cout << ans << endl;
}

int main(){
freopen("tricount.in","r",stdin);
freopen("tricount.out","w",stdout);
input();
qsort(a+1,n,sizeof(Point),cmp);
solve();
}

[USACO Elite 2010 U S Open Competition GOLD slide]拓扑排序、动态规划

【题目地址】http://ace.delos.com/ioigate
【题目大意】
有中文的。。。略了。
【算法分析】
题目给出一个信息:无环。
于是topsort。
然后逆拓扑序dp回来。
F[i,j]表示到达第i个点,已经失控j次,所能得到的最坏积分。
然后转移的话,程序里有,很简短,就不写了。
【CODE】
/*
ID:jie22221
TASK:slide
LANG:C++
*/
#include #include #include #include using namespace std;
typedef long long lld;
const int N=50005;
const int E=150005;
const lld INF=(lld)(1)<<60;
struct gtp{int x,y,w,next;}g[E];
int n,m,L,e;
int ls[N],du[N],list[N];
lld F[N][11];

void input(){
scanf("%d %d %d",&n,&m,&L);
for (int i=1,x,y,w;i<=m;i++){
scanf("%d%d%d",&x,&y,&w);
g[++e].x=x; g[e].y=y; g[e].w=w; g[e].next=ls[x]; ls[x]=e;
du[y]++;
}
}

void bfs(){
int head=0,tail=0,i,t;
for (i=1;i<=n;i++)
if (!du[i]) list[++tail]=i;
while (head head++;
for (t=ls[list[head]];t;t=g[t].next){
du[g[t].y]–;
if (!du[g[t].y]) list[++tail]=g[t].y;
}
}
}

void dp(){
memset(F,200,sizeof(F));
F[n][0]=0;
int i,j,k,t;
lld Min,Max;
for (k=n;k>=1;k–){
i=list[k];
for (j=0;j<=L;j++){
Min=INF;
if (j){
for (t=ls[i];t;t=g[t].next)
if (F[g[t].y][j-1]>=0 && F[g[t].y][j-1]+g[t].w Min=F[g[t].y][j-1]+g[t].w;
}
Max=0;
for (t=ls[i];t;t=g[t].next)
Max=max(Max,F[g[t].y][j]+g[t].w);
F[i][j]=min(Max,Min);
}
}
cout << F[1][L] << 'n';
}

int main(){
freopen("slide.in","r",stdin);
freopen("slide.out","w",stdout);
input();
bfs();
dp();
}

[COCI 2009/2010 – Constest #7 RESTORAN]贪心骗分、未A、非完美算法

【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
一个N,E<=10^5的无向图
每条边可以染黑白两色。
求一个染色方案,使每一个度>1的点,都拥有与之相连的黑边和白边。
【算法分析】
。。。我只会骗分了,应该还可以写个随机调整搞一下。
我是把它当树来走,树边染上dep[p] mod 2+1的颜色。
然后其他边如果只有某一边需要,那么就完成那一边的需求。
否则随便完成某一边的需求。
【数据通过情况】
Test # Score Time Memory Result 1 0.0 0.00s 6956 kB You program printed 0, but there is a valid solution. 2 6.5 0.00s 6956 kB Correct! 3 6.5 0.00s 6956 kB Correct! 4 0.0 0.00s 6956 kB You program printed 0, but there is a valid solution. 5 0.0 0.00s 6956 kB Correct! 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB Correct! 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.00s 6956 kB Correct! 0.00s 6956 kB Correct! 6 0.0 0.11s 10000 kB Correct! 0.09s 6956 kB Correct! 0.00s 6956 kB You program printed 0, but there is a valid solution. 0.11s 10000 kB You program printed 0, but there is a valid solution. 0.10s 7916 kB You program printed 0, but there is a valid solution. 0.11s 8592 kB You program printed 0, but there is a valid solution. 0.11s 7720 kB Correct! 0.10s 8248 kB You program printed 0, but there is a valid solution.
显然。。。因为它搞到多组测试数据,完全没办法得很多分。。。但是过的点也不少了。。。
求正解
【CODE】
#include #include #include const int N=105555;
struct edge{int x,y,color,next,op;}g[N*2];
int n,e;
int ls[N],dep[N],du[N],donec[N],fa[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].x=y; g[e].y=x; g[e].next=ls[y]; ls[y]=e; g[e].op=e-1;
}

void init(){
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]++;
}
}

inline void draw(int t,int co){
if (g[t].color) return;
if (co==3 || co==1){
g[t].color=1;
g[g[t].op].color=1;
}
else{
g[t].color=2;
g[g[t].op].color=2;
}
if (!donec[g[t].x]) donec[g[t].x]=co;
if (donec[g[t].x]!=co) donec[g[t].x]=3;
if (!donec[g[t].y]) donec[g[t].y]=co;
if (donec[g[t].y]!=co) donec[g[t].y]=3;
}

void dfs(int p){
for (int t=ls[p];t;t=g[t].next)
if (!dep[g[t].y]){
dep[g[t].y]=dep[p]+1;
fa[g[t].y]=t;
draw(t,dep[p]%2+1);
dfs(g[t].y);
}
else if (g[t].op!=fa[p]){
if (donec[g[t].y]==3) draw(t,3-donec[p]);
else if (donec[g[t].y]==donec[p]) draw(t,3-donec[p]);
else draw(t,donec[p]);
}
}

void work(){
int i;
for (i=1;i<=n;i++)
if (!dep[i]){
dep[i]=1;
dfs(i);
}
}

void update(int p){
donec[p]=0;
for (int t=ls[p];t;t=g[t].next){
if (!donec[p]) donec[p]=g[t].color;
if (donec[p]!=g[t].color) {donec[p]=3; return;}
}
}

bool Try_opc(int ss){
for (int t=ls[g[ss].x];t;t=g[t].next)
if (g[t].color==g[ss].color && t!=ss){
g[ss].color=3-g[ss].color;
g[g[ss].op].color=g[ss].color;
donec[g[ss].x]=3;
update(g[ss].y);
return true;
}
return false;
}

void solve(){
bool flag=true;
for (int i=1;i<=n;i++)
for (int t=ls[i];t && du[i]>1 && donec[i]!=3;t=g[t].next)
if (Try_opc(t)) break;
for (int i=1;i<=n;i++)
if (du[i]>1 && donec[i]!=3){
flag=false;
}
if (!flag){
printf("0n");
return;
}
for (int i=1;i printf("%dn",g[i].color);
}

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

[COCI 2009/2010 – Constest #7 KRALJEVI]矩阵上的各种维护 & 分类讨论

【题目地址】http://evaluator.hsin.hr/login.php?redirect=index.php
【题目大意】
在一个m*n的矩阵里,给出一些国际象棋中的王,让你求出所有王对(。。。就是那些点对)之间最小到达步数的和。
【算法分析】

LU[i][j]表示以(i,j)为右下角的这个矩形内的所有的王跳到(i,j)这个位置一共跳了多少步。
LS[i][j]表示以(i,j)为右下角的这个矩形内的所有的王的数目。
RU[i][j]和RS[i][j]同上。
UU[i][j]表示以从(1,j)到(i,j)这一路下来的王跳到(i,j)一共跳的步数。
US[i][j]表示以从(1,j)到(i,j)这一路下来一共有多少个王。

然后就是设法维护一下,像dp一样,并不是很难。
【CODE】
#include #include #include long long LU[1005][1005],RU[1005][1005],UU[1005][1005];
int LS[1005][1005],RS[1005][1005],US[1005][1005];
char c[1005][1005];

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

void solve(){
int i,j;
memset(LS,0,sizeof(LS));
memset(RS,0,sizeof(RS));
memset(LU,0,sizeof(LU));
memset(RU,0,sizeof(RU));

long long ans=0;
for (i=1;i<=m;i++){
for (j=1;j<=n;j++){
LU[i][j]=LU[i][j-1]+LS[i][j-1];
LS[i][j]=LS[i][j-1];
if (c[i][j]==’M’){
LS[i][j]++;
ans+=LU[i][j];
}
}
for (j=n;j>=1;j–){
RU[i][j]=RU[i][j+1]+RS[i][j+1];
RS[i][j]=RS[i][j+1];
if (c[i][j]==’M’) RS[i][j]++;
}
for (j=1;j<=n;j++){
UU[i][j]=UU[i-1][j]+US[i-1][j];
US[i][j]=US[i-1][j];
if (c[i][j]==’M’){
US[i][j]++;
ans+=UU[i][j];
}
}

for (j=1;j<=n;j++){
if (c[i][j]==’M’)
ans+=LU[i-1][j-1]+LS[i-1][j-1]+RU[i-1][j+1]+RS[i-1][j+1];
LU[i][j]+=LU[i-1][j-1]+LS[i-1][j-1]+UU[i-1][j]+US[i-1][j];
LS[i][j]+=LS[i-1][j-1]+US[i-1][j];
RU[i][j]+=RU[i-1][j+1]+RS[i-1][j+1]+UU[i-1][j]+US[i-1][j];
RS[i][j]+=RS[i-1][j+1]+US[i-1][j];
}
}

printf("%lld",ans);
}

int main(){
init();
solve();
printf(" ");
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++){
if (c[i][j]==’M’) c[i][j]=’.’;
if (c[i][j]==’S’) c[i][j]=’M’;
}
solve();
printf("n");
}