洛谷11月月赛round.1

太感动了
#2 thwfhk 240 (801ms) 100 100 40
 
又一张明信片,话说10月的怎么还没收到
 



 

P2246 SAC#1 - Hello World(升级版)

题目背景

一天,智障的pipapi正在看某辣鸡讲义学程序设计。

题目描述

在讲义的某一面,他看见了一篇文章。这篇文章由英文字母(大小写均有)、数字、和空白字符(制表/空格/回车)构成。

pipapi想起了他最近刚刚学会写的Hello World程序。他非常好奇,这篇文章中,“HelloWorld”作为子序列到底出现过多少次呢?

由于papapi是个智障,大小写对于他而言毫无区别;因此,“hEllOWorLD”这样的子序列也是可以接受的。O和W之间的空格是也是可以少的;也就是说,“HelloWorld”是可以的。根据标程的意思,就是没有空格,不用考虑空格的情况。

两个子序列相同当且仅当它们每一个字符所在的位置都相同。

由于答案可能很大,请输出结果对1000000007(10^9+7)的余数。

输入输出格式

输入格式:

 

输入包含若干行。这些行的内容共同构成一篇文章。

文章以EOF(文件结尾)结束。

 

输出格式:

 

输出仅包含一个整数,表示这篇文章中“Hello World”出现的次数。 

 

输入输出样例

输入样例#1:
HhEeLlLlOoWwOoRrLlDd
输出样例#1:
1536
输入样例#2:
Gou Li Guo Jia Sheng Si Yi
Qi Yin Huo Fu Bi Qu Zhi
River can feed people
Also can race boats
Hall Ellen Ok Words locked 
输出样例#2:
273

说明

记n为输入的文章的长度(字符数)。

对于20%的数据,n <= 20。

对于50%的数据,n <= 500。

对于所有的数据,15 <= n <= 500000。


 

直接秒掉,f[i][j]前i个0到j匹配方案数,滚掉第一维

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=5e5+5,MOD=1e9+7;
int n,m,p,mp[300];
char c;
int f[12];

int main(){
    char s[12]="helloworld";
    for(int i=0;i<10;i++) mp[s[i]]=1;

    while((c=getchar())!=EOF){
    if((c>='A'&&c<'Z')||(c>='a'&&c<='z')){
        if(c<'a') c+='a'-'A';
        if(!mp[c]) continue;
        //printf("%c\n",c);
        if(c=='h') f[1]++;
        else if(c=='e') f[2]+=f[1],f[2]%=MOD;
        else if(c=='l'){
            f[4]+=f[3],f[4]%=MOD;
            f[3]+=f[2],f[3]%=MOD;
            f[9]+=f[8],f[9]%=MOD;
        }else if(c=='o'){
            f[5]+=f[4],f[5]%=MOD;
            f[7]+=f[6],f[7]%=MOD;
        }else if(c=='w') f[6]+=f[5],f[6]%=MOD;
        else if(c=='r') f[8]+=f[7],f[8]%=MOD;
        else if(c=='d') f[10]+=f[9],f[10]%=MOD;
        
    }
    }
    printf("%d",f[10]);
}

 

 




P2247 SAC#1 - ACOJ云评测计划

题目背景

本题由世界上最蒟蒻最辣鸡最撒比的SOL提供。

寂月城网站是完美信息教室的官网。地址:http://191.101.11.174/mgzd 。

题目描述

ACOJ的服务器简直是差到了一个令人发指的地步。于是SAC的出题人,也就是傻逼SOL,不得不强制要求每一个通过下载ACOJ软件包而搭建的分站,都为主站启动云端评测服务。

云评测服务是由网络来连接的。这样的网络连接是双向的;但是由于地理位置等因素的限制,并不是任意两台服务器都可以直接相连。ACOJ主站已经得到了可以直连的服务器的表,其中包含n个分站(包括主站)以及它们的m条连接情况,可以根据这个来分配各个分站的任务。

有一些分站的服主是SOL的脑残粉。他们会无条件地将他们的服务器提供给SOL。这些ACOJ分站称作“好站”。但是还有一些分站的服主是SOL黑。他们虽然拿到了ACOJ的服务端,但是并不愿意为SOL提供资源,于是利用黑科技关掉了云服务。也就是说,虽然主站仍然认为这些站点存在,但是它们不会起到任何作用——既不能传递通信,也不能进行评测。它们称作“坏站”。

经过千辛万苦的调查,SOL确定了ACOJ云评测系统中有最多k个坏站存在,而且这k个坏站似乎会使得ACOJ的云网络不再联通!大危机!

但是SOL太弱智了,并不能确定是哪k个。于是他请你来帮他找出任意一组可能会使得网络不再联通的k个站点,以便加强防范。

输入输出格式

输入格式:

 

输入包含m+1行。

第1行3个整数n、m、k。

接下来m行,每行两个整数a、b,表示标号为a和b的站点可以直接相连。

 

输出格式:

 

输出包含1行。

不超过k个整数,表示能够将原图割开的任意一组节点组合。

因为使用了Special Judge,所以节点的顺序并不用担心。只需要满足能够割开原图即可。

如果不存在这样的站点集合,输出“How oversuspicious you are, SOL!”;如果网络不存在任何坏站时本来就无法连通,输出“Poor SOL!”。

 

输入输出样例

输入样例#1:
4 4 2
1 2
2 3
3 4
4 1
输出样例#1:
1 3
输入样例#2:
4 6 2
1 2
2 3
3 4
4 1
1 3
2 4 
输出样例#2:
How oversuspicious you are, SOL!
输入样例#3:
4 0 2
输出样例#3:
Poor SOL!

说明

对于20%的数据,n <= 15。

对于另外20%的数据,n <= 100,k=1。

对于另外20%的数据,n <= 100,k=2。

对于100%的数据,3 <= n <= 500,k <= 3,n-k >= 2,云网络不存在自环和重边。


枚举再求割点

 也可以每次重构图

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int N=505;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,k,a,b;
struct edge{
    int v,w,ne;
}e[N*N<<1];
int h[N],cnt=0;
inline void ins(int u,int v){
    cnt++;
    e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}

int dfn[N],low[N],dfc,scc,iscut[N],cv,nc;
void init(){
	for(int i=0;i<=n;i++) dfn[i]=low[i]=iscut[i]=0;
	dfc=scc=cv=0;
}
void dfs1(int u,int fa){ nc++;
	dfn[u]=low[u]=++dfc;
	int child=0;
	for(int i=h[u];i;i=e[i].ne){
		int v=e[i].v;
		if(!dfn[v]){
			child++;
			dfs1(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]) iscut[u]=1;
		}else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
	if(fa==0&&child==1) iscut[u]=0;
	if(iscut[u]) cv=u;
}

void dfs2(int u,int fa,int del){
	dfn[u]=low[u]=++dfc;
	int child=0;
	for(int i=h[u];i;i=e[i].ne){
		int v=e[i].v; if(v==del) continue;
		if(!dfn[v]){
			child++;
			dfs2(v,u,del);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]) iscut[u]=1;
		}else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
	if(fa==0&&child==1) iscut[u]=0;
	if(iscut[u]) cv=u;
}

void dfs3(int u,int fa,int del1,int del2){
	dfn[u]=low[u]=++dfc;
	int child=0;
	for(int i=h[u];i;i=e[i].ne){
		int v=e[i].v; if(v==del1||v==del2) continue;
		if(!dfn[v]){
			child++;
			dfs3(v,u,del1,del2);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]) iscut[u]=1;
		}else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
	if(fa==0&&child==1) iscut[u]=0;
	if(iscut[u]) cv=u;
}
int main(){
	n=read();m=read();k=read();
	for(int i=1;i<=m;i++){a=read();b=read();ins(a,b);}
	
	dfs1(1,0);
	if(nc<n) {puts("Poor SOL!");return 0;}
	else if(cv) {printf("%d",cv);return 0;}
	
	init();
	if(k==2){
		dfs2(2,0,1);
		if(cv){printf("%d %d",1,cv);return 0;}
		
		for(int i=2;i<=n;i++){
			init();
			dfs2(1,0,i);
			if(cv){printf("%d %d",i,cv);return 0;} 
		}
	}else if(k==3){
		dfs3(3,0,1,2);
		if(cv){printf("%d %d %d",1,2,cv);return 0;}
		for(int i=3;i<=n;i++){
			init();
			dfs3(2,0,1,i);
			if(cv){printf("%d %d %d",1,i,cv);return 0;}
		}
		for(int i=2;i<=n;i++)
			for(int j=i+1;j<=n;j++){
				init();
				dfs3(1,0,i,j);
				if(cv){printf("%d %d %d",i,j,cv);return 0;} 
			}
	}
	puts("How oversuspicious you are, SOL!");
	return 0;
}

 




 

P2248 分段

题目描述

给定你n个数,要求将它们分成若干连续的段。

要求:

  1. 有m对给定的数不能被分到同一段。

  2. 分出一个段的代价是,其中K和S均为给定的常数,而P则是该段中所有数的最大值,Q是该段中所有数的最小值。

  3. 要求你求出每段代价之和最小的分段方案。

输入输出格式

输入格式:

 

第一行两个正整数n和m,表示数的个数和不能共存的m对数。

第二行两个非负整数K和S,含义见题面。

第三行n个非负整数,即给定的n个数。

接下来m行每行2个数,表示这两个编号的数不能共存。(编号从1开始)

 

输出格式:

 

输出仅一行,表示最小的每段代价之和。

 

输入输出样例

输入样例#1:
5 2
3 1
2 3 12 14 16
2 3
3 1
输出样例#1:
11

说明

对于10%的数据,

对于30%的数据,

对于另外10%的数据,

对于另外30%的数据,

对于100%的数据,1≤m,n≤100000,0≤K,S,a_i≤100000,1≤pi,qi≤n,pi≠qi。

 


 

想了个O(n^2)的DP就打上了,特判了一下S==0,好像没什么用

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const ll INF=1e18;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,m,K,S,a[N],pos[N],p,q;
int mx[N][17],mn[N][17];
void initRMQ(){
    for(int i=1;i<=n;i++) mx[i][0]=mn[i][0]=a[i];
    
    for(int j=1;j<=16;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]),
            mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r){
    int k=log(r-l+1)/log(2);
    return max(mx[l][k],mx[r-(1<<k)+1][k])-min(mn[l][k],mn[r-(1<<k)+1][k]);
}

ll f[N];
void dp(){
    for(int i=1;i<=n;i++){
        f[i]=INF;int p=pos[i];
        for(int j=i-1;j>=p;j--){
            f[i]=min(f[i],f[j]+K+(ll)S*(ll)rmq(j+1,i));
            p=max(p,pos[j]);
        }
    }
}
struct range{
    int a,b;
    bool operator <(const range &r)const{return b<r.b;}
}d[N];
void sol(){
    int cnt=0;
    for(int i=1;i<=n;i++) if(pos[i]) d[++cnt]=(range){pos[i],i};
    
    sort(d+1,d+1+cnt);
    int last=0,ans=0;
    for(int i=1;i<=cnt;i++){
        if(d[i].a<=last) continue;
        last=d[i].b;
        ans++;
    }
    printf("%d",ans*K+K);
}

int main(){
    n=read();m=read();K=read();S=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=m;i++){
        p=read();q=read();
        if(p>q) swap(p,q);
        pos[q]=max(pos[q],p);
    }
    if(S==0){
        sol();
    }else{    
        initRMQ();
        dp();
        printf("%lld",f[n]);
    }
}

 

posted @ 2016-11-12 22:44  Candy?  阅读(563)  评论(0编辑  收藏  举报