LCP Array Accepts: 131
Submissions: 1352
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
Problem Description
Peter has a string s=s1s2…sns=s_{1}s_{2}…s_{n}s=s1s2…sn, let suffi=sisi+1…sn\text{suff}i =s{i}s_{i+1}…s_{n}suffi=sisi+1…sn be the suffix start with iii-th character of sss. Peter knows the lcp (longest common prefix) of each two adjacent suffixes which denotes as ai=lcp(suffi,suffi+1)(1≤i
#include<iostream>
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<vector>
#include<string.h>
int T;
int n;
int a[100005];
long long an=1;
int MOD=1000000007;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int flag=1;
an=26;
for(int i=1;i<n;i++)
{
scanf("%d",&a[i]);
if(a[i]!=a[i-1]-1&&a[i-1]>0)
{
flag=0;
}
}
if(flag==0||a[n-1]>1)
{
printf("0\n");
continue;
}
for(int i=1;i<n;i++)
if(a[i]==0)
an=(an*25)%MOD;
printf("%I64d\n",an);
}
}
Shortest Path Accepts: 40
Submissions: 610
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
Problem Description
There is a path graph G=(V,E)G=(V,E)G=(V,E) with nnn vertices. Vertices are numbered from 111 to nnn and there is an edge with unit length between iii and i+1i + 1i+1 (1≤i
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int di[8][8];
int n,m;
int a[8];
int aa,bb;
int an;
long long ans;
int abs(int x)
{
if(x<0) return -x;
return x;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=6;i++)
scanf("%d",&a[i]);
for(int i=1;i<=6;i++)
for(int j=1;j<=6;j++)
{
di[i][j]=100005;
}
for(int i=1;i<=6;i++)
{
di[i][i]=0;
for(int j=1;j<=6;j++)
{
if((i&1)&&j==i+1)
{
di[j][i]=di[i][j]=min(abs(a[j]-a[i]),1);
}
else di[i][j]=di[j][i]=min(abs(a[j]-a[i]),di[i][j]);
}
}
//cout<<" "<<di[1][2]<<endl;
for(int k=1;k<=6;k++)
for(int i=1;i<=6;i++)
for(int j=1;j<=6;j++)
if(i!=j&&j!=k&&k!=i)
di[i][j]=min(di[i][j],di[i][k]+di[k][j]);
ans=0;
for(int ii=1;ii<=m;ii++)
{
scanf("%d%d",&aa,&bb);
an=abs(aa-bb);
for(int i=1;i<=6;i++)
for(int j=1;j<=6;j++)
{
int QQ=di[i][j]+abs(aa-a[i])+abs(bb-a[j]);
if(an>QQ) an=QQ;
}
//cout<<an<<endl;
ans=(ans+ii*an)%1000000007;
}
cout<<ans%1000000007<<endl;
}
}
Transform Accepts: 7
Submissions: 49
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
问题描述
给出nnn个整数, 对于一个整数xxx, 你可以做如下的操作若干次:
- 令xxx的二进制表示为b31b30…b0‾\overline{b_{31}b_{30}…b_0}b31b30…b0, 你可以翻转其中一个位.
- 令yyy是给出的其中一个整数, 你可以把xxx变为x⊕yx \oplus yx⊕y, 其中⊕\oplus⊕表示位运算里面的异或操作.
现在有若干整数对(S,T)(S, T)(S,T), 对于每对整数你需要找出从SSS变成TTT的最小操作次数.
输入描述
输入包含多组数据. 第一行有一个整数TTT (T≤20)(T \le 20)(T≤20), 表示测试数据组数. 对于每组数据:
第一行包含两个整数nnn和mmm (1≤n≤15,1≤m≤105)(1 \le n \le 15, 1 \le m \le 10^5)(1≤n≤15,1≤m≤105), 表示给出整数的数目和询问的数目. 接下来一行包含nnn个用空格分隔的整数a1,a2,…,ana_1, a_2, …, a_na1,a2,…,an (1≤ai≤105)(1 \le a_i \le 10^5)(1≤ai≤105).
接下来mmm行, 每行包含两个整数sis_isi和tit_iti (1≤si,ti≤105)(1 \le s_i, t_i \le 10^5)(1≤si,ti≤105), 代表一组询问.
输出描述
对于每组数据, 输出一个整数S=(∑i=1mi⋅zi) mod (109+7)S=(\displaystyle\sum_{i=1}^{m} i \cdot z_i) \text{ mod } (10^9 + 7)S=(i=1∑mi⋅zi) mod (109+7), 其中ziz_izi是第iii次询问的答案.
输入样例
1
3 3
1 2 3
3 4
1 2
3 9
输出样例
10
Hint
3→43 \to 43→4 (2次操作): 3→7→43 \to 7 \to 43→7→4
1→21 \to 21→2 (1次操作): 1⊕3=21 \oplus 3 = 21⊕3=2
3→93 \to 93→9 (2次操作): 3→1→93 \to 1 \to 93→1→9
solution: 1.DP 2.bfs
add edge from 0 :1.(1<
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
long long a[18+15+1];
long long ans;
int MAXN=131072+1;
long long MOD=1e9+7;
int dp[131073*2];
int n,m;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=0;i<18;i++)
{
a[++n]=(1<<i);
}
for(int i=1;i<MAXN;i++) dp[i]=99999;
for(int i=1;i<=n;i++)
for(int j=0;j<MAXN;j++)
{
dp[a[i]^j]=min( dp[a[i]^j],dp[j]+1 );
}
for(int i=1;i<=m;i++)
{
int aa,bb;
scanf("%d%d",&aa,&bb);
ans=(ans+(long long )dp[aa^bb]*(long long )i)%MOD;
}
cout<<ans<<endl;
}
}
Toposort Accepts: 7
Submissions: 25
Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
问题描述
给出nnn个点mmm条边的有向无环图. 要求删掉恰好kkk条边使得字典序最小的拓扑序列尽可能小.
输入描述
输入包含多组数据. 第一行有一个整数TTT, 表示测试数据组数. 对于每组数据:
第一行包含3个整数nnn, mmm和kkk (1≤n≤100000,0≤k≤m≤200000)(1 \le n \le 100000, 0 \le k \le m \le 200000)(1≤n≤100000,0≤k≤m≤200000), 表示图中结点数目, 图中边的数目以及要删的边数.
接下来mmm行, 每行包含两个整数uiu_iui and viv_ivi, 表示存在一条uiu_iui到viv_ivi的有向边 (1≤ui,vi≤n)(1 \le u_i, v_i \le n)(1≤ui,vi≤n).
输入保证给定的图是一个DAG. 输入数据中nnn的和不超过10610^6106. 输入数据中mmm的和不超过2⋅1062 \cdot 10^62⋅106.
输出描述
对于每组数据, 输出一个整数S=(∑i=1ni⋅pi) mod (109+7)S = (\displaystyle\sum_{i=1}^{n}{i\cdot p_i}) \text{ mod } (10^9 + 7)S=(i=1∑ni⋅pi) mod (109+7), 其中p1,p2,…,pnp_{1}, p_{2}, …, p_{n}p1,p2,…,pn是字典序最小的那个拓扑序列.
输入样例
3
4 2 0
1 2
1 3
4 5 1
2 1
3 1
4 1
2 3
2 4
4 4 2
1 2
2 3
3 4
1 4
输出样例
30
27
30
solution 1:Toposort
参考下普通的用堆维护求字典序最小拓扑序, 用某种数据结构维护入度小于等于kkk的所有点, 每次找出编号最小的, 并相应的减少kkk即可.
这个数据结构可以用线段树, 建立一个线段树每个节点[l,r][l,r][l,r]维护编号从lll到rrr的所有节点的最小入度, 查询的时候只需要在线段树上二分, 找到最小的xxx满足入度小于等于kkk.
复杂度O((n+m)logn)O((n+m)\log n)O((n+m)logn)
solution 2:
maintain a pri. queue to faster locate the curent best answer;
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#define mod 1000000007
using namespace std;
int T;
int n,m,k;
int aa,bb;
int r[100005];
int vis[100005];
vector<int> lin[100005];
int tot;
long long ans;
priority_queue<int> q;
void TP()
{
tot=0;
while(tot<n)
{
int now=-q.top();
q.pop();
if(r[now]>k||vis[now]==1) continue;
vis[now]=1;
k-=r[now];
r[now]=0;
tot++;
ans+=(long long)tot*(long long)now;
ans%=mod;
for(int i=0;i<lin[now].size();i++)
{
int nex=lin[now][i];
if(r[nex])
{
r[nex]--;
q.push(-nex);
}
}
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
ans=0;
while(!q.empty()) q.pop();
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
lin[i].clear();
vis[i]=r[i]=0;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&aa,&bb);
lin[aa].push_back(bb);
r[bb]++;
}
for(int i=1;i<=n;i++) q.push(-i);
TP();
cout<<ans<<endl;
}
}