您的位置:首页 > 其它

2012天津现场赛

2013-01-21 20:35 239 查看
这场去了天津现场,做的明显不如网赛来的顺利,感觉自己准备的很不充分啊,努力刷题吧~~

Str2int

用后缀自动机来搞。将给定的串用10这个字符连接起来,建一个SAM,然后按照节点代表的串长度bfs一下,来一个dp就可以求出答案了。

如果用SA来解,必须预处理后在O(1)的时间得到[l,r]区间的所有前缀和,蛋疼。

还是最简状态自动机简单些。明显状态和阶段都好了,dp一下就出来了,具体看代码。

#include<cstdio>
#include<cstdlib>
#include<queue>
#include<vector>
#include<string.h>
using namespace std;
const int MAX=410003;
const int NUM=12;
const char BASE='0';
const int mod=2012;
#define End
struct node{
node* ch[NUM],*fa;
int len,hash,num;
#ifdef End
int end;
#endif
node(){}
node(node* father,int lenth)
{
fa=father;
len=lenth;
hash=0;num=0;
#ifdef End
end=0;
#endif
memset(ch,0,sizeof ch);
}
}tree[MAX],*Root;
int cnt;
bool vis[MAX];
void SAM(char* a,int n){
cnt=0;
memset(tree,0,sizeof(tree));
Root=tree+(cnt++);
*Root=node(0,0);
node *p=Root,*np,*op,*cp;
int i,idx;
for(i=0;i<n;++i)
{
idx=a[i]-BASE;
np=tree+(cnt++);
*np=node(0,i+1);
np->num=0;
#ifdef End
np->end=i;
#endif
while(p && !p->ch[idx])
p->ch[idx]=np,p=p->fa;
if(p && p->ch[idx])
{
op=p->ch[idx];
if(p->len+1==op->len)
np->fa=op;
else
{
cp=tree+(cnt++);
*cp=*op;
cp->num=0;
#ifdef End
cp->end=i;
#endif
cp->len=p->len+1;
op->fa=cp;np->fa=cp;
while(p && p->ch[idx]==op)
p->ch[idx]=cp,p=p->fa;
}
}
else np->fa=Root;
p=np;
}
}int n,m;
char s[MAX];
vector<node*> hh[MAX];
int bfs()
{
memset(vis,0,sizeof(vis));
int sum=0,idx,i,j;
Root->num=1;
for(i=0;i<=n;++i)
while (!hh[i].empty()) hh[i].clear();
for(i=0;i<cnt;++i)
hh[tree[i].len].push_back(tree+i);
for(i=0;i<=n;i++)
for(j=hh[i].size()-1;j>=0;--j)
{
if (!hh[i][j]->num) continue;
for (idx=0; idx<10; idx++)
{
if (hh[i][j]==Root && idx==0) continue;
if (hh[i][j]->ch[idx]){
hh[i][j]->ch[idx]->hash+=
hh[i][j]->hash*10+idx*hh[i][j]->num;
hh[i][j]->ch[idx]->hash%=mod;
hh[i][j]->ch[idx]->num+=hh[i][j]->num;
sum+=hh[i][j]->hash*10+idx*hh[i][j]->num;
sum%=mod;
}
}
}
return sum;
}
int main()
{
int m,sum,i,len;
char *sp;
while ( ~scanf("%d",&m) )
{
memset(s,0,sizeof(s));
n=sum=0;
sp=s;
for (i=0; i<m; i++)
{
scanf("%s",sp);
len=strlen(sp);
sp+=len;
*(sp++)='0'+10;
}
*sp=0;
n=strlen(s);
SAM(s,n);
sum=bfs();
printf("%d\n",sum);
}
return 0;
}


charge-station

简单贪心题。城市i的费用比所有小于i的城市费用和都高(这个在二进制下很容易看出来)。

所以先假设全部城市都建加油站,check()一下,不满足题意就puts("-1");

然后从高到低逐个删去城市,如果check()满足,那么果断删掉,如果出现不满足的情况,就不能删掉。重复此过程一直到第二个城市。

最后输出结果,为了方便题目叫我们直接输出二进制。

(-这么简单的题居然没做,低头....(-

#include<cstdio>
#include<cstring>
#include<cmath>
const int N = 130;
struct node{
int x,y;//maybe in double;
}a
;
int n,d;
int g

;
int distance(node &a, node &b){
int ret,dx,dy;
dx=a.x-b.x, dy=a.y-b.y;
ret=sqrt( dx*dx+dy*dy );
if (ret*ret == dx*dx + dy*dy) return ret;
else return ret+1;
}
bool vis
;
int q
,ans
;
bool check(){
int i,head,tail,t;
memset(vis,0,sizeof(vis));
vis[0]=1, q[0]=0, head=1, tail=0;
while (tail<head){
t=q[tail++];
for (i=0; i<n; i++)
if (!vis[i]){
if (ans[i]){
if (g[t][i]<=d) {
q[head++]=i, vis[i]=1;
//printf("@%d %d\n",t,i);
}
}else{
if (g[t][i]+g[i][t]<=d) {
vis[i]=1;
//printf("@%d %d\n",t,i);
}
}
}
}
for (i=0; i<n; i++) if (vis[i]==0) return false;
return true;
}
void solve(){
int i;
for (i=0; i<n; i++) ans[i]=1;
if (!check()) {
puts("-1");
return ;
}
for (i=n-1; i>0; i--){
ans[i]=0;//assert
//printf("@erase:%d\n",i);
if (!check()) {
ans[i]=1;
}
}
i=n-1;
while (ans[i]==0) i--;

for (; i>=0; i--) if (ans[i]) printf("1");else printf("0");
puts("");
}
int main(){
int i,j;
while ( ~scanf("%d%d",&n,&d) ){
for (i=0; i<n; i++)
scanf("%d %d", &a[i].x, &a[i].y);
for (i=0; i<n; i++)
for (j=0; j<n; j++)
g[i][j]=distance(a[i],a[j]);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: