链接:戳这里
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[n]=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; }
题意:两个操作,一是将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; }
题意:给出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; }