您的位置:首页 > 其它

BestCoder 74

2016-03-07 16:57 316 查看
链接:戳这里

A:LCP Array
题意:给定一个字符串s=s1s2s3s4...s5,si代表字符(小写字母),知道任意两个相邻的后缀的最长公共前缀长度为一个整数ai,这个意思就是相邻字符相等的个数为ai。问满足该字符串s的种数。

思路:样例

4

3 2 1

aaaa

  aaa

    aa

      a

显然这样的字符串必须是 aaaa (26字符任意一个) 才能满足条件,对于相邻两个数不为0且相差不为1,的肯定是不存在的

3

0 0

三个字符中  中间的字符不能与两旁的相同  ans=26*25*25

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
#define mod 1000000007
using namespace std;
int T,n;
int a[1001000];
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int num=0;
for(int i=1;i<n;i++) scanf("%d",&a[i]);
int flag=0;
ll ans=26;
a
=0;
for(int i=1;i<n;i++){
if(a[i]==0) {
ans*=25;
ans%=mod;
continue;
}
if(a[i] && a[i]==a[i+1]+1) continue;
else {
flag=1;
break;
}
}
if(flag==1) cout<<0<<endl;
else printf("%I64d\n",ans);
}
return 0;
}


B:Shortest
Path

题意:有一条长度为n的链. 节点i和i+1之间有长度为1的边. 现在又新加了3条边, 每条边长度都是1. 给出m个询问, 每次询问两点之间的最短路.

思路:链上两点之间距离,可以是不过加的边答案是两点之间的距离,加的三条边在链上新增加了6个点,每个点都可以是新的通道,那么就在这6个点上跑最短路,计算从从s->t的距离。复杂度O(64*m)

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
#define mod 1000000007
using namespace std;
int T;
int n,m;
int u[8],c[8][8],dis[8],vis[8];
ll ans;
int solve(){
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
c[i][j]=fabs(u[i]-u[j]);
}
}
c[0][1]=c[1][0]=1;
c[2][3]=c[3][2]=1;
c[4][5]=c[5][4]=1;
mst(vis,0);
for(int i=0;i<8;i++) dis[i]=maxn;
dis[6]=0;
for(int i=0;i<8;i++){
int minn=maxn,g=-1;
for(int j=0;j<8;j++){
if(!vis[j] && dis[j]<minn){
minn=dis[j];
g=j;
}
}
vis[g]=1;
for(int j=0;j<8;j++){
if(!vis[j] && dis[j]>dis[g]+c[g][j]){
dis[j]=dis[g]+c[g][j];
}
}
}
return dis[7];
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
ans=0;
for(int i=0;i<3;i++) scanf("%d%d",&u[i<<1],&u[i<<1|1]);
for(int i=1;i<=m;i++){
scanf("%d%d",&u[6],&u[7]);
ans+=((ll)i*solve()%mod+mod)%mod;
ans%=mod;
}
printf("%I64d\n",ans);
}
return 0;
}

C:Transform

题意:两个操作,一是将x二进制上的01翻转一次变成另外一个数,而是x抑或一个数y变成另外一个数,给N个y提供选择,问最少需要多少次操作才能使S->T

思路:第一个操作其实就是x抑或2的次方,缩成一个操作,x抑或n个数或者抑或2的次方求操作数最少。

由于S^a1^a2^...an=T  ==>  a1^a2^...an=S^T  抑或满足交换律; 接下来就是从0开始,从(2的次方,a[1~n])中挑选数抑或最后值为S^T, SPFA的思路正好解决了这个问题。复杂度O(
(n+17)log(n+17) +m )

代码: 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
#define mod 1000000007
using namespace std;
int T,n,m;
int a[55],dis[200100],vis[200100];
queue<int> qu;
void SPFA(){
mst(vis,0);
mst(dis,-1);
vis[0]=1;dis[0]=0;
qu.push(0);
while(!qu.empty()){
int now=qu.front();
qu.pop();
vis[now]=0;
for(int i=0;i<n;i++){
int u=a[i]^now;
if(dis[u]!=-1 && dis[u]<=dis[now]+1) continue;
dis[u]=dis[now]+1;
if(!vis[u]){
vis[u]=1;
qu.push(u);
}
}
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<17;i++){
a[i+n]=(1<<i);
}
n+=17;

SPFA();

ll ans=0;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
ans+=(ll)dis[x^y]*i;
///printf("%I64d\n",ans);
ans%=mod;
}
printf("%I64d\n",ans);
}
return 0;
}


D:Toposort

题意:给出n个点m条边的有向无环图. 要求删掉恰好k条边使得字典序最小的拓扑序列尽可能小.

思路:字典序最小的拓扑排序,首先我们只能删除入度<=K的节点,满足的节点又需要选择字典序最小的点,需要处理这两个操作,第一个操作可以用数组存在每个节点的入度然后放入线段树,线段树每个点存最小的点,第二个操作直接在线段树上找字典序最小的<=k的点。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
#define INF (1ll<<60)-1
#define mod 1000000007
using namespace std;
int T,n,m,k,tot;
struct edge{
int next,v;
}e[200100];
int head[100100],d[100100],tr[400100];
void init(){
mst(head,-1);
mst(d,0);
tot=0;
}
void add(int u,int v){
e[tot].v=v;
e[tot].next=head[u];
head[u]=tot++;
}
void build(int root,int l,int r){
if(l==r){
tr[root]=d[l];
return ;
}
int mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
tr[root]=min(tr[root*2],tr[root*2+1]);
}
int query(int root,int l,int r,int K){
if(l==r) return l;
int mid=(l+r)/2;
if(tr[root*2]<=K) return query(root*2,l,mid,K);
else return query(root*2+1,mid+1,r,K);
}
void update(int root,int l,int r,int w){
if(l==w && r==w){
tr[root]=d[w];
return ;
}
int mid=(l+r)/2;
if(w<=mid) update(root*2,l,mid,w);
else update(root*2+1,mid+1,r,w);
tr[root]=min(tr[root*2],tr[root*2+1]);
}
int main(){
scanf("%d",&T);
while(T--){
init();
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
d[v]++;
}
build(1,1,n);
ll ans=0;
for(int i=1;i<=n;i++){
int w=query(1,1,n,k);
///printf(" %%  %%\n");
ans+=((ll)i*w);ans%=mod;
k-=d[w];
d[w]=MAX;
update(1,1,n,w);
///printf("%%%%  \n");
for(int j=head[w];j!=-1;j=e[j].next){
d[e[j].v]--;
///printf("&&&^%^&%\n");
update(1,1,n,e[j].v);
}
}
printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: