题号 标题 已通过代码 通过率 团队的状态
A Car Show 点击查看 1347/3168
B Two Frogs 点击查看 777/2832
C Global Positioning System 点击查看 41/136
D Half Turns 点击查看 9/28
E Longest Increasing Subsequence 点击查看 183/1423
F Matrix and GCD 点击查看 79/369
G Magic Spells 点击查看 461/3045
H Radar Scanner 点击查看 0/79
I The Great Wall II 点击查看 173/929
J Colourful Journey 点击查看 2/25
K NIO’s OAuth2 Server 点击查看 70/282
链接:https://ac.nowcoder.com/acm/contest/33194/A
来源:牛客网
题目描述
There are nn cities and mm car styles in NIO Kingdom. According to the investigations, for the ii-th city, cars of style T_iT
i
are the most popular.
Now there will be a car show in NIO Kingdom, and the person in charge wants to choose an integer interval [l,r][l,r] (1\le l \le r \le n)(1≤l≤r≤n) and let the cities whose indices are in this interval hold the show jointly. And to manifest the variety of the cars, every style should occur at least once among the most popular styles in the host cities. Determine the number of integer intervals satisfying the constraint mentioned before.
输入描述:
The first line contains two integers nn and mm (1 \le m \le n \le 100,000)(1≤m≤n≤100000), denoting the number of cities and the number of car styles respectively.
The second line contains nn integers T_1, T_2, \cdots, T_nT
1
,T
2
,⋯,T
n
(1 \le T_i \le m)(1≤T
i
≤m), denoting the most popular styles.
输出描述:
Output one line containing one integer, denoting the answer.
示例1
输入
复制
5 3
1 2 3 2 1
输出
复制
5
说明
For the sample case, the 55 intervals are [1, 3], [1, 4], [1, 5], [2, 5], [3, 5][1,3],[1,4],[1,5],[2,5],[3,5] respectively.
题意:
思路:
#include
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
int a[maxn], b[maxn];
int main(){
ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
int n, m; cin>>n>>m;
for(int i = 1; i <= n; i++)cin>>a[i];
set<int>se;
LL ans = 0;
for(int l=1, r=0; l <= n; l++){
while(r<=n && se.size()<m){
r++;
se.insert(a[r]);
b[a[r]]++;
}
ans += n-r+1; //对于当前的l, 从r开始包含所有1~m
b[a[l]]--; //l从当前区间去掉
if(b[a[l]]==0)se.erase(a[l]);
}
cout<<ans<<"\n";
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/33194/B
来源:牛客网
题目描述
In the Lonely Mountain, there are a lot of treasure well protected by dwarfs. Later, one day, the last dragon Smaug came and sensed the treasure being. As known to all, dragons are always much too greedy for treasure. So definitely, the war between dwarfs and Smaug begins.
During the war, two goblins Alice and Bob are turned into frogs by Gandalf, The Grey. In front of them, there are nn lotus leaves in a line. In order to break the spell, they must jump from the 11-st lotus leaf to the nn-th lotus leaf. If the frog is now on the ii-th lotus leaf instead of the nn-th lotus leaf, it can jump to a lotus leaf in range (i, i + a_i](i,i+a
i
].
Goblins are lack of intelligence and it’s also true even after turned into frogs. So Alice and Bob will jump randomly, which means, they will separately pick an available lotus leaf in every jump uniformly at random.
Since Alice and Bob have already being playing games for decades, so they want to know the probability that they jump to the nn-th lotus leaf with the same count of jumps.
输入描述:
The first line contains an integer nn (2 \leq n \leq 8,000)(2≤n≤8000), denoting the number of lotus leaf.
The second line contains n-1n−1 integers a_1, a_2, \ldots, a_{n-1}a
1
,a
2
,…,a
n−1
, where the ii-th integer a_ia
i
(1 \leq a_i \leq n-i)(1≤a
i
≤n−i) indicates the range of lotus leaves that can be reached from the ii-th lotus leaf.
输出描述:
Output a line containing a single integer, indicating the probability that Alive and Bob jump to nn-th lotus leaf with the same count of jumps, taken modulo 998,244,353998244353.
Formally speaking, let the result, which is a rational number, be \frac{x}{y}
y
x
as an irreducible fraction, you need to output x \cdot y^{-1} \bmod{998,244,353}x⋅y
−1
mod998244353, where y^{-1}y
−1
is a number such that y \cdot y^{-1} \equiv 1 \pmod{998,244,353}y⋅y
−1
≡1(mod998244353). You may safely assume that such y^{-1}y
−1
always exists.
示例1
输入
复制
5
1 1 1 1
输出
复制
1
示例2
输入
复制
5
4 3 2 1
输出
复制
440198031
题意:
思路:
//时间优化
#include
using namespace std;
typedef long long LL;
const LL maxn = 8010, mod = 998244353;
void exgcd(LL a, LL b, LL &d, LL &x, LL & y, LL MOD) { if (b==0) { d = a; x = 1; y = 0; } else { exgcd(b, a % b, d, y, x, MOD); y -= x * (a / b); } }
LL inv(LL a, LL MOD) { LL d=0, x=0, y=0; exgcd(a, MOD, d, x, y, MOD); return d == 1 ? (x + MOD) % MOD : -1; }
LL a[maxn], b[maxn], dp[maxn][maxn]; //到达位置i,走了j步的概率
int main(){
ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
LL n; cin>>n;
for(int i = 1; i < n; i++)cin>>a[i], b[i]=inv(a[i],mod);
dp[1][0] = 1; dp[2][0] = -1;
for(int i = 1; i <= n; i++){
for(int k = 0; k < i; k++){
//前缀和更新
dp[i][k]=(dp[i][k]+dp[i-1][k])%mod;
//转移:dp[i+1,i+a[i]][k+1] += dp[i][k]/a[i]
dp[i+1][k+1]=(dp[i+1][k+1]+dp[i][k]*b[i])%mod;
dp[i+a[i]+1][k+1]=(dp[i+a[i]+1][k+1]-dp[i][k]*b[i])%mod;
// for(int j=i+1;j<=i+a[i];j++){
// dp[j][k+1]=(dp[j][k+1]+dp[i][k]*inv(a[i],mod)+mod)%mod;
// }
}
}
LL ans = 0;
for(int i = 1; i < n; i++)ans = (ans+dp[n][i]*dp[n][i]%mod)%mod;
cout<<ans<<"\n";
return 0;
}
//空间优化
#include
using namespace std;
typedef long long LL;
const int maxn = 8010, mod = 998244353;
void exgcd(LL a, LL b, LL &d, LL &x, LL & y, LL MOD) { if (b==0) { d = a; x = 1; y = 0; } else { exgcd(b, a % b, d, y, x, MOD); y -= x * (a / b); } }
LL inv(LL a, LL MOD) { LL d=0, x=0, y=0; exgcd(a, MOD, d, x, y, MOD); return d == 1 ? (x + MOD) % MOD : -1; }
LL a[maxn], b[maxn], dp[maxn];
int main(){
ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
LL n; cin>>n;
for(int i = 1; i < n; i++)cin>>a[i], b[i] = inv(a[i],mod), a[i]=min(n,i+a[i])+1;
LL ans = 0;
dp[1] = 1;
for(int i = 0; i <= n; i++){ //dp[j]:跳i次跳到第j个荷叶的概率
ans = (ans+dp[n]*dp[n]%mod)%mod;
dp[n] = 0;
for(int j = n-1; j >= 0; j--){ //通过荷叶j来跳第i次,概率*1/a[j]
LL t = dp[j]*b[j]%mod; //概率+=dp[i-1][j]*1/a[j]
dp[j+1] = (dp[j+1]+t+mod)%mod; //给[j+1,j+a[j]] += t
dp[a[j]] = (dp[a[j]]-t+mod)%mod;
dp[j] = 0;
}
for(int j = 1; j <= n; j++){ //前缀和更新
dp[j] = (dp[j]+dp[j-1])%mod;
}
}
cout<<ans<<"\n";
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/33194/G
来源:牛客网
题目描述
One day in the magic world, the young wizard RoundDog was learning the compatibility of spells. After experimenting for a long time, he reached the conclusion that the compatibility of a spell collection can be measured by the number of distinct palindromes that are substrings of all the spells in the collection. He was so excited and planned to write a program to calculate the compatibility of any input spell collection.
However, RoundDog was busy participating the NowWizard Multi-Universe Training this week. He was too struggling during the competition and feels tired now.
Since RoundDog is not in the mood to finish the program now, could you help him?
输入描述:
The first line contains a single integer kk (1 \leq k \leq 5)(1≤k≤5), indicating the number of spells in a spell collection.
In the following kk lines, each line contains a spell SS (1 \le |S| \le 300,000)(1≤∣S∣≤300000), which is a string containing only lowercase English letters.
It is guaranteed that the total length of the spells does not exceed 300,000300000.
输出描述:
Output the compatibility of the input spell collection, which is the number of distinct palindromes that are substrings of all the spells in the collection.
示例1
输入
复制
3
abaca
abccaca
acabb
输出
复制
4
说明
In the example, “a”, “b”, “c”, “aca” are the four distinct palindromes that are substrings of all the input spells.
题意:
思路:
//manacher+hash
#include
using namespace std;
typedef long long LL;
const int maxn = 6e5+10;
char s[maxn];
map<pair<LL,LL>,int>mp; //字符串[l,r]的出现次数
//字符串双值hash(降低冲突)
const LL mod = 1000000007, mod2 = 998244353, base = 146;
char ch[maxn];
LL Sum1[maxn], Pow1[maxn], Sum2[maxn], Pow2[maxn], N;
void init(){
Pow1[0] = Pow2[0] = 1;
for (int i = 1; i <= 300000; i ++){
Pow1[i] = Pow1[i-1] * base % mod;
Pow2[i] = Pow2[i-1] * base % mod2;
}
}
void init_str(char *s){
int n = strlen(s + 1);
ch[0] = '@'; ch[n*2+1] = '#'; ch[n*2+2] = '\0';
Sum1[0] = Sum2[0] = 0;
for (int i = 1; i <=n; i++){
Sum1[i] = (Sum1[i-1] * base % mod + s[i]) % mod;
Sum2[i] = (Sum2[i-1] * base % mod2 + s[i]) % mod2;
ch[i*2] = s[i];
ch[i*2-1] = '#';
}
N = 2*n+1;
}
inline pair<LL,LL> get_hash(int l, int r){
LL hash1 = (Sum1[r] - Sum1[l-1] * Pow1[r - l + 1] % mod + mod) % mod;
LL hash2 = (Sum2[r] - Sum2[l-1] * Pow2[r - l + 1] % mod2 + mod2) % mod2;
return {hash1, hash2};
}
//马拉车,求s的本质不同的回文子串
int r[maxn];
void manacher(int id){
r[1] = 1; //r[i]:以i为中心的最长回文子串
int k = 1;
for(int i = 2; i <= N; i++){
int p = k+r[k]-1;
if(i <= p)r[i] = min(r[2 * k - i], p - i + 1); //没有超过边界,用对称性求解
else r[i] = 1; //至少为1
while(ch[i+r[i]] == ch[i-r[i]])r[i]++; //超过边界时,暴力匹配
//枚举以i为中心的回文串, k维护已经枚举过的边界
if (i + r[i] > k + r[k]){
for (int R = k+r[k]+1; R <=i+r[i]; R++){
int L = 2*i-R;
//判断回文串[L,R], 如果次数<当前id,就去掉
if(ch[R]=='#'){
pair<LL,LL>hashvalue = get_hash(L/2+1,R/2);
if(id>1 && !mp.count(hashvalue))continue;
if(id>1 && mp[hashvalue]<id-1){
mp.erase(hashvalue); continue;
}
if(mp[hashvalue] == id)continue;
mp[hashvalue] = id;
}
}
k = i;
}
}
}
int main(){
init();
int n; scanf("%d",&n);
for(int i = 1; i <= n; i++){
scanf("%s", s+1);
init_str(s);
manacher(i);
}
int ans = 0;
for(auto x : mp){
if(x.second==n)ans++;
}
cout<<ans<<"\n";
return 0;
}
//回文自动机
#include
using namespace std;
const int maxn = 6e5+10;
//Palindromic Tree, 仅接受某个字符串的所有回文子串的中心及右半部分, O(n)
struct PAM{
int ch[maxn][27],s[maxn],fail[maxn],len[maxn],num[maxn],cnt[maxn];
int n,tot,last;
int newnode(int x){len[tot]=x;return tot++;}//建立一个新节点,长度为x
void init(){ //初始化
newnode(0);newnode(-1); //状态0和-1,分别作为偶回文子串和奇回文子串两棵树的根
fail[0]=1;fail[1]=1;
n=last=0;s[n]=-1;
}
//找后缀回文
//fail边,表示真后缀中在自动机里的最长状态(也就是最长回文真后缀)
int getfail(int x){while(s[n]!=s[n-len[x]-1])x=fail[x];return x;}
//建树
//性质:在一个字符串后添加一个字符,至多增加一个之前没有出现过的回文子串,且该回文子串必定是原串的一个回文真后缀两侧加上新添加的这个字符
void add(int x,int pos,int id){
s[++n]=x; //当前添加的字符为x
int t=getfail(last); //找上次到达的状态, 往后添加一个字符
if(!ch[t][x]){ //如果后一个字符的状态不存在,就新建
int now=newnode(len[t]+2); //转移表示在串的两侧各加上同一个字符,因此len+2
fail[now]=ch[getfail(fail[t])][x];
ch[t][x]=now;
num[now]=num[fail[now]]+1;
}
last=ch[t][x]; //跳转到当前状态
cnt[last]|=(1<<id); //状压,记录在第id个里存在该回文串
}
void build(char *s,int id){
int N=strlen(s);
for(int i=0;i<N;++i)add(s[i]-'a'+1,i,id);
}
}pam;
char s[maxn];
int main(){
pam.init();
int n; scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%s",s);
pam.last = 0; pam.n = 0; //对每个串重新跑回文自动机(维护cnt不删)
pam.build(s,i);
}
int ans = 0;
for(int i=0;i<pam.tot;++i){ //遍历回文树所有节点
ans += (pam.cnt[i]==((1<<n)-1)); //如果某个串在n次里都出现了,ans+1
}
cout<<ans<<"\n";
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/33194/E
来源:牛客网
题目描述
Given an integer mm, you need to construct a permutation pp whose length does not exceed 100100 such that there are exactly mm longest increasing subsequences in pp.
If multiple solutions exist, print any of them. If no solution exists, report it.
输入描述:
The first line contains an integer TT (1\le T \le 1,000)(1≤T≤1000), denoting the number of test cases.
Each test case contains an integer mm (1\le m \le 10^9)(1≤m≤10
9
) in one line.
输出描述:
For each test case:
If no solution exists, print “-1” (without quotes) in one line.
Otherwise, print one integer nn (1\le n\le 100)(1≤n≤100) in the first line denoting the length of the permutation you construct. Then print nn integers p_1, p_2, \cdots, p_np
1
,p
2
,⋯,p
n
, (1 \le p_i \le n, \forall , 1 \le i < j \le n, p_i \neq p_j)(1≤p
i
≤n,∀1≤i
=p
j
) in the second line denoting the permutation you construct.
示例1
输入
复制
2
3
5
输出
复制
4
2 4 1 3
5
3 2 5 1 4
说明
In the first test case, the length of the LIS (longest increasing subsequence) is 22, and the 33 LISs are {2, 4}, {2, 3}, {1, 3}{2,4},{2,3},{1,3}.
In the second test case, the length of the LIS is 22, and the 55 LISs are {3, 5}, {3, 4}, {2, 5}, {2, 4}, {1, 4}{3,5},{3,4},{2,5},{2,4},{1,4}.
题意:
思路:
#include
using namespace std;
int main(){
ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
int T; cin>>T;
while(T--){
int m; cin>>m;
int len = 32-__builtin_clz(m);
vector<int>cnt(len); //2i位后需要插入的数字个数
for(int i = 0,lt=-1; i < len; i++){ //lt维护每个1后面连续的0的个数
if(m>>i&1)cnt[lt=i]++; //对于这位为1至少要插入一个
else if(lt>=0)cnt[lt]++; //0则是插在上个1的后面
}
vector<int>res;
int low=0, high=2*len-2;
for(int i = 0; i < len; i++){
if(i>0)res.push_back(low+2),res.push_back(low+1), low+=2;
for(int j = 0; j < cnt[i]; j++)res.push_back(++high);
}
cout<<res.size()<<"\n";
for(int i = 0; i < res.size(); i++){
cout<<res[i]<<" \n"[i+1==res.size()];
}
}
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/33194/I
来源:牛客网
题目描述
Beacon towers are built throughout and alongside the Great Wall. There was once a time when there were nn beacon towers built from west to east for defending against the invaders. The altitude of the ii-th beacon tower, based on historical records, is a_ia
i
.
The defenders divide strategically all beacon towers into kk parts where each part contains several, but at least one, consecutive beacon towers. To fully defend against the invaders, to each part a team of defenders should be assigned, the cost of which is given by the highest altitudes of beacon towers in that part.
As a historian, you are dying to know the minimum costs of assignments for every k = 1, 2, \ldots, nk=1,2,…,n.
输入描述:
The first line contains an integer nn (1 \leq n \leq 8,000)(1≤n≤8000), denoting the number of beacon towers alongside the Great Wall.
The second line contains nn integers a_1, a_2, \ldots, a_na
1
,a
2
,…,a
n
, where the ii-th integer a_ia
i
(1 \leq a_i \leq 100,000)(1≤a
i
≤100000) is the altitude of the ii-th beacon tower.
输出描述:
Output nn lines, the ii-th of which contains an integer indicating the minimum cost for k = ik=i.
示例1
输入
复制
5
1 2 3 4 5
输出
复制
5
6
8
11
15
示例2
输入
复制
5
1 2 1 2 1
输出
复制
2
3
4
6
7
题意:
思路:
𝑑𝑝(𝑖,𝑗)表示将𝑎1,𝑎2,…,𝑎𝑗分为𝑖段的最小代价。
转移时已经知道分为i-1段的最小代价,枚举k
对于固定的𝑗,当𝑘从𝑗开始遍历到1时,max{𝑎𝑘,𝑎(𝑘+1),…,𝑎j}是不减的,每一个取值对应一段𝑘。
新增一个𝑎(𝑗+1)时末尾一些段会被合并成一个max值是𝑎(𝑗+1)的段,可以使用单调栈维护所有段。
每个数最多入栈和出栈一次,因此遍历一次整个数组时维护单调栈的复杂度是𝑂(𝑛)。
假设当前的段是[𝑙1,𝑟1],[𝑙2,𝑟2],…,[𝑙𝑠,𝑟𝑠],对应的max值是𝑣1,𝑣2,…,𝑣𝑠。
转移式改写为𝑑p(𝑖,𝑗)=min(1≤𝑡≤𝑠){min{𝑑𝑝(𝑖−1,𝑙𝑡 ),𝑑𝑝(𝑖−1,𝑙𝑡+1),…,𝑑𝑝(𝑖−1,𝑟_𝑡 )}+𝑣𝑡}。
#include
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PLL;
const int maxn = 8010;
LL a[maxn], dp[maxn][maxn]; //将前i个数分为j段的最小代价(每一段的最大值之和)
int main(){
int n; cin>>n;
for(int i = 1; i <= n; i++)cin>>a[i];
memset(dp, 0x3f, sizeof dp);
dp[0][0] = 0; dp[1][1] = a[1];
for(int i = 2; i <= n; i++)dp[i][1] = max(dp[i-1][1], a[i]);
for(int j = 2; j <= n; j++){ //枚举划分为j段的最小代价
vector<PLL>stk; //维护每一段最大值的位置和对应的最小代价,单调递减
stk.push_back({0,dp[0][j-1]});
for(int i = 1; i <= n; i++){ //考虑把第i个数放到前面的某一段里去
LL mi = dp[i-1][j-1]; //第i个数单独成段的最小代价
while(stk.back().first!=0 && a[stk.back().first]<a[i]){
mi = min(mi,stk.back().second); //最大值
stk.pop_back();
}
//a[i]可以放到最大值>当前的段里,不需要代价。 或者单独成段,代价+a[i]。
dp[i][j] = min(dp[stk.back().first][j], mi+a[i]);
stk.push_back({i,min(mi, dp[i][j-1])});
}
}
for(int i = 1; i <= n; i++)cout<<dp[n][i]<<"\n";
return 0;
}