Name | Date | Rank | Solved | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2020 Multi-University,Nowcoder Day 2 | 2020.7.18 | 78/1178 | 8/12 | O | O | O | O | O | O | O | Ø | × | × | × | O |
A.Clam and Fish(贪心)
题目描述
一共 \(n(1\leq n\leq 2\times 10^6)\) 天,每天有下述四种状态中的一种:
- 无鱼无饵
- 无鱼有饵
- 有鱼无饵
- 有鱼有饵
有鱼可以拿鱼,有饵可以拿饵,无鱼可以用一个饵拿鱼,或什么都不做,四种操作只能选一个,求最多能拿多少鱼。
分析
首先明确,要是当前的状态有鱼,那么直接抓鱼。若当前为状态 \(2\),那么用鱼饵钓鱼显然不如直接抓鱼实惠;若当前状态为 \(3\),虽然可以获得鱼饵,但是获得鱼饵也是为了在将来花费这个鱼饵钓到鱼,问题是将来可能不会再有钓鱼的机会(鱼饵多余,已经是最后一天……),不如放弃这个鱼饵,直接抓鱼。
若当前状态没有鱼,那么鱼饵要尽量在没有蛤蜊的时候用掉,有蛤蜊的状态用来获取鱼饵。若当前状态为 \(0\),什么都没有;那么有鱼饵的话直接用来抓鱼,否则就什么都不做。若当前状态为 \(1\),如果没有鱼饵,那就不必思考,直接获取鱼饵;如果有鱼饵,再来考虑要不要钓鱼;因为鱼饵是为将来状态为 \(0\) 的时候准备的,如果钓鱼后,拥有的鱼饵足够将来状态为 \(0\) 的那几天使用,就可以放心地钓鱼,否则就将蛤蜊做成鱼饵。
值得一提的是,需要逆向预处理第 \(i\) 天后状态为 \(0\) 的天数,再正向进行贪心。
代码
/******************************************************************
Copyright: 11D_Beyonder All Rights Reserved
Author: 11D_Beyonder
Problem ID: 2020牛客暑期多校训练营(第三场) Problem A
Date: 8/14/2020
Description: Greedy
*******************************************************************/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2000005;
int _;
char days[N];
int n;
int leftover[N];
int bait,fish;
inline void init();
int main(){
for(cin>>_;_;_--){
scanf("%d%s",&n,days+1);
init();
int i;
for(i=n;i>=1;i--){
leftover[i]+=days[i]=='0';
leftover[i]+=leftover[i+1];
}
for(i=1;i<=n;i++){
if(days[i]=='0'){
//没鱼 没蛤蜊
if(bait){
//有鱼饵 可以抓鱼
bait--;
fish++;
}
}else if(days[i]=='1'){
//没鱼 有蛤蜊
if(!bait){
//没鱼饵 只能将蛤蜊做成鱼饵
bait++;
}else{
//有鱼饵 考虑要不要抓鱼
if(leftover[i]<bait){
//当前鱼饵足够在后面没鱼没蛤蜊的情况下抓鱼
//现在可以抓鱼
fish++;
bait--;
}else{
//做成鱼饵 在将来没鱼没蛤蜊的情况下抓鱼
bait++;
}
}
}else{
//有鱼直接抓 不能错失机会
fish++;
}
}
printf("%d\n",fish);
}
return 0;
}
inline void init(){
bait=fish=0;
fill(leftover,leftover+n+2,0);
}
B.Classical String Problem(模拟)
题目描述
给一个字符串 \(S\),下标从 \(1\) 开始,\(q\) 次询问,每一组有一个字符 \(op\),一个数字 \(x\),当 \(op=A\) 时,输出当前字符串第 \(x\) 个字符;当 \(op=M\) 时,如果 \(x>0\),把字符串最左边的 \(x\) 个字符放到字符串右边,如果 \(x<0\),把字符串最右边 \(|x|\) 个字符放到字符串左边。
数据范围:\(2\leq |S|\leq 2\times 10^6,1\leq q\leq 8\times 10^5\)。
分析
小模拟,对于一个字符串,存在两种操作,一种是将字符串长度为 \(x\) 的前缀移动到后面,或者将后缀移动到前面,另一种是查询当前第 \(x\) 个字符是什么。对于前后缀的移动可以认为字符串是一个环形的,只要移动环形的入口位置即可,定义变量 \(base\) 为第\(0\)个字符,移动的时候让 \(base\) 加上 \(x\),查询的时候查询\(base+x\) 位置的字符。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
string str;
cin >> str;
int base = -1;
int len = str.size();
int n;
cin >> n;
while (n--)
{
char s[2];
int x;
scanf("%s%d", s, &x);
if (s[0] == 'A')
{
int tmp = base + x;
if (tmp < 0)
{
tmp += len * ((abs(tmp)) / len + 1);
}
tmp %= len;
putchar(str[tmp]);
putchar('\n');
}
else
{
base += x;
}
}
return 0;
}
C.Operation Love(思维+模拟)
题目描述
给出一个手掌的形状(\(20\) 个点),判断图形是左手还是右手(可能旋转 \(45^{\circ}\),但大小不会变化)。
分析
首先观察得仅存在一个点\((O)\):大拇指根部的点,与其相连的两条边长度分别是 \(6\) 和 \(9\),那么遍历所有的点,找到其与相邻两点之间的距离,最终定位到点 \(O\),并将整个图形进行平移,让点 \(O\) 与原点重合,与\(O\) 相连的两个边形成一个直角,此时只需要判断与 \(O\) 相邻的两个点在坐标轴上的关系即可判断是左右手。
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
struct node
{
db x, y;
};
node input[20];
node num[20];
int qq, hj;
db dis(node& a, node& b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void trans()
{
int base = 0;
for (int i = 0; i < 20; i++)
{
int l = (i - 1 + 40) % 20;
int r = (i + 1) % 20;
db ll = dis(input[i], input[l]);
db rr = dis(input[i], input[r]);
if ((fabs(ll - 9.0) < 1e-2 && fabs(rr - 6.0) < 1e-2) || (fabs(ll - 6.0) < 1e-2 && fabs(rr - 9.0) < 1e-2))
{
base = i;
break;
}
}
for (int i = 0; i < 20; i++)
{
num[i] = input[(i + base) % 20];
}
for (int i = 19; i >= 0; i--)
{
num[i].x -= num[0].x;
num[i].y -= num[0].y;
}
if (fabs(dis(num[0], num[1]) - 9.0) < 1e-2)
{
hj = 1;
qq = 19;
}
else
{
hj = 19;
qq = 1;
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
for (int i = 0; i < 20; i++)
{
scanf("%lf%lf", &input[i].x, &input[i].y);
}
trans();
node chang = num[hj];
node duan = num[qq];
bool wa = false;
if (duan.x >= 0.0 && duan.y > 0.0)
{
if (chang.x > 0.0 && chang.y <= 0.0)wa = true;
}
else if (duan.x > 0.0 && duan.y <= 0.0)
{
if (chang.x <= 0.0 && chang.y < 0.0)wa = true;
}
else if (duan.x <= 0.0 && duan.y < 0.0)
{
if (chang.x < 0.0 && chang.y >= 0.0)wa = true;
}
else
{
if (chang.x >= 0.0 && chang.y > 0.0)wa = true;
}
if (wa)puts("right");
else puts("left");
}
return 0;
}
D.Points Construction Problem(构造)
题目描述
在二维平面内,每个格点(整数点)有一个白点,可以将其中一些点涂黑。问能否将 \(n(1\leq n\leq 50)\) 个白点涂黑,使得有 \(m(1\leq m\leq 200)\) 对相邻的白点和黑点(相邻指曼哈顿距离为 \(1\))。
分析
在平面上用小正方形构造一个可以分散的,面积为 \(n\),周长和为 \(m\) 的不规则图形。首先考虑 \(n\) 与 \(m\) 的关系,显然,当 \(n\) 个小正方形互相不接触的时候是周长和最大的情况,此时 \(m=4\times n\),当 \(n\) 个小正方形尽可能堆积成一个大正方形的时候,周长是最小的,此时 \(m=2\times(\lceil\sqrt{n}\rceil+\lceil\frac{n}{\lceil\sqrt{n}\rceil}\rceil)\),另外,考虑对于每一个不规则图形的一条边,总存在另一条边与其对应,周长应该总是一个偶数,当 \(m\) 是奇数的时候同样无法构造答案。
具体构造方法,可以认为一开始所有的小正方形都是排列在一条斜线上的,此时总周长是 \(4\times n\),此时可以将后面的小正方形一个个取出来,放在与前面正方形相接触的位置,如果放置的位置与一个正方形相接触,总周长 \(-2\),如果和两个接触,总周长 \(-4\)。再考虑要保证能够构造出周长最小的情况,因此需要一层一层来膜最开始的一个正方形,具体构造顺序可以认为如下:
1 | 2 | 5 | 10 | 17 |
---|---|---|---|---|
3 | 4 | 6 | 11 | 18 |
7 | 8 | 9 | 12 | 19 |
13 | 14 | 15 | 16 | 20 |
21 | 22 | 23 | 24 | 25 |
一直按这样的顺序来构造,直到最后总周长等于 \(m\) 的时候停止,此时剩余的所有方块在一个较远的位置摆放成一条斜线。需要特别注意,如果某一时刻要构造的位置会让周长减 \(4\),但是此时周长和 \(m\) 的差值只有 \(2\),可以特别地在第一个方块的上面放一个方块,然后结束构造,即可规避这种特殊情况。
代码
#include<bits/stdc++.h>
using namespace std;
int mp[50][50];
int main()
{
int t;
cin >> t;
while (t--)
{
memset(mp, 0, sizeof(mp));
int n, m;
scanf("%d%d", &n, &m);
if (m & 1 || m > 4 * n)
{
puts("No");
continue;
}
int tmp = 4 * n - m;
mp[1][1] = 1;
int step = 2;
while (tmp && step <= 10)
{
int tt = 2 * step - 1;
tt *= 4;
tt -= 4;
if (tmp >= tt)
{
for (int i = 1; i <= step; i++)
{
mp[step][i] = mp[i][step] = 1;
}
step++;
tmp -= tt;
continue;
}
if (tmp)
{
mp[step][1] = 1;
tmp -= 2;
}
int cnt = 2;
while (tmp >= 4 && cnt < step)
{
mp[step][cnt] = 1;
tmp -= 4;
cnt++;
}
if (tmp)
{
mp[1][step] = 1;
tmp -= 2;
}
cnt = 2;
while (tmp >= 4 && cnt <= step)
{
mp[cnt][step] = 1;
tmp -= 4;
cnt++;
}
if (tmp)
{
mp[0][1] = 1;
tmp -= 2;
}
step++;
}
int sum = 0;
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j <= 10; j++)
{
if (mp[i][j])sum++;
}
}
if (sum > n)puts("No");
else
{
puts("Yes");
n -= sum;
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j <= 10; j++)
{
/*if (mp[i][j])
printf("■");
else printf(" ");*/
if (mp[i][j])
printf("%d %d\n", i, j);
}
/*putchar('\n');*/
}
for (int i = 0; i < n; i++)
{
printf("%d %d\n", i + 1000, i + 1000);
}
}
}
return 0;
}
E.Two Matchings(dp)
题目描述
\(p=[p_1,p_2,\cdots,p_n]\) 是一个长为 \(n\) 的全排列。
定义一个全排列是一个 匹配,当且仅当 \(\forall i,p_i\neq i\ 且\ p_{p_i}=i\)。
对于数组 \(a=[a_1,a_2,\cdots,a_n](0\leq a_i\leq 10^9,n\geq 4)\) 且 \(n\) 是偶数,定义全排列的价值为 \(\frac{\displaystyle\sum_{i=1}^{n}\Big|a_i-a_{p_i}\Big|}{2}\)。
定义两个 匹配 \(p,q\) 是 可组合 的,当且仅当 \(\forall i,p_i\neq q_i\)。
找到两个 可组合 的 匹配,使得这两个 匹配 的总价值尽可能小,输出价值之和。
数据范围:\(n\) 的总和不超过 \(2\times 10^5,0\leq a_i\leq 10^9\)。
分析
要想使总价值最小,需要找到价值最小的排列和价值最小的排列。
价值最小的排列很容易找到,把 \(a\) 序列排序后两两配对计算价值即可。
下文中均假设序列已经排好序。
对于 \(a\) 序列有 \(4\) 个数字的情况,可以发现次小价值为 \(a[4]-a[2]+a[3]-a[1]=a[4]+a[3]-a[2]-a[1]\)。
对于有 \(a\) 序列 \(6\) 个数字的情况,可以发现次小价值为 \(a[3]-a[2]+a[5]-a[4]+a[6]-a[1]\)。
对于更长的序列,一定可以拆分成长为 \(4\) 和长为 \(6\) 的序列,转化成了子问题。
设 \(dp[i]\) 为前 \(i\) 个数的次大 价值。
状态转移方程为:
代码
#include<bits/stdc++.h>
using namespace std;
const int N=200100;
const long long INF=1ll<<60;
long long a[N],dp[N];
int main()
{
int T;
cin>>T;
while(T--)
{
long long ans=0,n;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+1+n);
for(int i=2;i<=n;i=i+2)
ans=ans+a[i]-a[i-1];
dp[2]=INF;
dp[4]=a[4]+a[3]-a[2]-a[1];
dp[6]=a[6]+a[5]+a[3]-a[4]-a[2]-a[1];
for(int i=8;i<=n;i=i+2)
dp[i]=min(dp[i-4]+a[i]+a[i-1]-a[i-2]-a[i-3],dp[i-6]+a[i]+a[i-1]+a[i-3]-a[i-2]-a[i-4]-a[i-5]);
printf("%lld\n",ans+dp[n]);
}
return 0;
}
F.Fraction Construction Problem(exgcd+构造)
题目描述
给出两个数字 \(a,b(1\leq a,b\leq 2\times 10^6)\),求任意一组满足下列条件的 \(c,d,e,f\):
-
\(\frac{c}{d}-\frac{e}{f}=\frac{a}{b}\)
-
\(d<b,f<b\)
-
\(1\leq c,e\leq 4\times 10^{12}\)
若无解,输出 \(-1\ -1\ -1\ -1\),\(1\leq T\leq 10^5\)。
分析
若 \(\gcd(a,b)\neq 1\) 时,令 \(c=2a,d=b,e=a,f=b\)。
若 \(b=1\),无解。
若 \(\gcd(a,b)=1\):
令 \(df=kb\)(\(k\) 为正整数)。
若 \(b\) 是质数,无解,因为 \(b\) 的因子只有 \(1\) 和 \(b\),\(d\) 和 \(f\) 只能取 \(b\) 的倍数,与 \(d<b,f<b\) 矛盾。
若 \(b\) 是某个质数的幂次方(即 \(p^k\)),无解。设 \(b=p^k,d=p^a\),则 \(f=p^{k-a}\),由扩展欧几里得算法可知 \(cf-de=a\) 的充要条件是 \(\gcd(d,f)|a\),所以 \(\gcd(d,f)=p^{\min(a,k-a)}\)。但是由于 \(\gcd(a,b)=1\),所以 \(p\nmid a\),即 \(\gcd(d,f)|a\),与前面所述矛盾。
所以 \(b\) 至少有两个质因子才有解,假设 \(b=p_1^{k_1}p_2^{k_2}\),则 \(d=p_1^{k_1-1}p_2^{k_2},f=p_1^{k_1}\),解方程 \(p_1c+p_2^{k_2}e=1\),解出 \(c,e\) 后,都乘上 \(a\),则:
代码
#include<bits/stdc++.h>
using namespace std;
long long T,a,b;
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
long long gcd=exgcd(b,a%b,x,y);
long long temp=x;x=y;y=temp-(a/b)*y;
return gcd;
}
const int N=2e6+10;
long long fac[N+10];
bool vis[N+10];
void init()
{
for(int i=2;i<=N;i++)
{
if(!vis[i])
{
for(int j=i;j<=N;j=j+i)
{
if(!vis[j])
fac[j]=i;
vis[j]=1;
}
}
}
}
int main()
{
init();
long long T;
cin>>T;
while(T--)
{
long long a,b;
scanf("%lld %lld",&a,&b);
long long gcd=__gcd(a,b);
a=a/gcd;b=b/gcd;
if(gcd>1)
{
printf("%lld %lld %lld %lld\n",a*2,b,a,b);
continue;
}
if(b==1)
{
printf("-1 -1 -1 -1\n");
continue;
}
gcd=b;
while(gcd%fac[b]==0)
gcd=gcd/fac[b];
if(gcd==1)
{
printf("-1 -1 -1 -1\n");
continue;
}
long long c;
long long d=b/fac[b];
long long e;
long long f=b/gcd;
exgcd(fac[b],gcd,c,e);
c=c*a;
e=e*a;
e=-e;
if(c<0)
{
swap(c,e);
swap(d,f);
c=-c;e=-e;
}
printf("%lld %lld %lld %lld\n",c,d,e,f);
}
return 0;
}
G.Operating on a Graph(并查集+启发式合并)
题目描述
给一个 \(n\) 个点,\(m\) 条边的无向图。点的编号从 \(0\) 到 \(n-1\)。一开始,点 \(i\) 属于团 \(i\)。定义团 \(A\) 与团 \(B\) 相连,当且仅当属于团 \(A\) 的点和属于团 \(B\) 的点之间至少有一条边相连。给定 \(q\) 次操作,每次操作给出 \(o_i\)。如果没有边属于团 \(o_i\),无事发生;否则所有与 \(o_i\) 相连的点都属于团 \(o_i\)。最后输出每个点属于哪个团。
数据范围:\(2\leq n\leq 8\times 10^5,1\leq m\leq 8\times 10^5,1\leq q\leq 8\times 10^5\)。
分析
可以发现,每个点被询问后,该点与其相邻点永远处于相同集合。
用并查集维护每个点属于哪个集合,再用 \(vector\) 存储该集合的外部连接点是哪几个。更新外部连接点的时候按照集合大小来合并,不然超内存。
代码
#include<bits/stdc++.h>
using namespace std;
int fa[800010];
int get(int x)
{
if(fa[x]==x)
return x;
return fa[x]=get(fa[x]);
}
vector<int> G[800010];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=0;i<=n;i++)
{
fa[i]=i;
G[i].clear();
}
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d %d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
int q;
scanf("%d",&q);
while(q--)
{
int o;
scanf("%d",&o);
if(fa[o]!=o)
continue;
vector<int> new_G=G[o];
G[o].clear();
for(int i=0;i<new_G.size();i++)
{
int v=get(new_G[i]);
if(v!=o)
{
fa[v]=o;
if(G[o].size()<G[v].size())//启发式合并
swap(G[o],G[v]);
for(int j=0;j<G[v].size();j++)
G[o].push_back(G[v][j]);
}
}
}
for(int i=0;i<n;i++)
printf("%d ",get(i));
puts("");
}
return 0;
}
H.Sort the Strings Revision(笛卡尔树+分治)
题目描述
给定一个初始字符串 \(s_0\),长度为 \(n\),第\(i\)个字符是 \(i\%10\),给定一个序列 \(p\) 和一个字符数组 \(d\),存在字符串 \(s_1\) ~ \(sn\),对于每一个字符串 \(s_i\),可以由前一个字符串 \(s_{i-1}\) 通过将第 \(p[i-1]\) 个位置的字符更改为 \(d[i]\) 来构造。将 \(s_0\) ~ \(s_n\) 按照字典序排序。
输入格式
\(T(1\leq T\leq 10^3)\) 组数据,首先输入 $n(1\leq n\leq 2\times 10^6) $ 代表字符串长度以及需要构造的 \(p\),\(d\) 的长度,随后依次给出 \(p_{seed},p_a,p_b,p_{mod}(0\leq p_{seed},p_a,p_b<p_{mod}\leq 10^9+7)\),\(d_{seed},d_a,d_b,d_{mod}(0\leq d_{seed},d_a,d_b< d_{mod}\leq 10^9+7\) 按照
的方式构造序列 \(p\),按照
的方式构造序列 \(d\),最终将 \(n+1\) 个字符串按照字典序从小到大将下标排序之后,输出\(\displaystyle{(\sum_{i=0}^{n}(r_i*10000019^i))\%1000000007}\)。
输出格式
考虑 \(n+1\) 个字符串,相邻两两之间最多只有一个字符不相同,而且每个字符只会被修改一次,修改之后可能会使字符串字典序变大,变小,也有可能完全不变。首先不考虑不变的情况,显然,对于第 \(0\) 个字符,当它发生改变的时候,可能会导致后面所有的字符串字典序变大或者变小,但是不论怎么变化,都会以当前位置为分界,将 \(n+1\) 个字符分成大小两段,而且不论两段内部如何排序,总是满足某一段的所有字符串大于另一段的所有字符串。在拆分后的任意一段内,可以再次找到最靠前的一个被修改的字符,继续将字符串分割成两部分,如此递归下去,便能得到所有字符串的大小关系。再考虑那些不对字符串字典序产生影响的改变,可以对这些改变忽视,只对有效的修改进行拆分,最终会得到数个小片段,一些小片段可能包含不止一个字符串,这些片段产生的原因就是那些没有发生改变的修改,对于这些字符串,根据题目要求,按照下标升序进行排列即可。
对于序列 \(p\) 建立笛卡尔树,便能在 \(O(n)\) 的时间内处理出每一次分治的位置,为了使那些不产生影响的修改被忽视,可以将对应位置的 \(p\) 中元素赋值为一个极大值,这样在笛卡尔树建立的过程中会将他们下沉到整个树的最低端,也就不会对上面的分治产生影响。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
const int maxn = 2000005;
const int inf = 0x7fffffff;
int st[maxn], l[maxn], r[maxn];
int p[maxn], d[maxn];
int rk[maxn];
void Cartesian(int n)//建笛卡尔树
{
int top = 0;
for (int i = 0; i < n; i++)
{
//l[i] = r[i] = -1;
while (top && p[st[top]] > p[i])
{
l[i] = st[top--];
}
if (top)
{
r[st[top]] = i;
}
st[++top] = i;
}
}
void dfs(int n, int L, int R, int rak)//分治
{
if (p[n] == inf || L >= R)//当前片段仅有一个元素或者当前片段的修改无效,可以按下表顺序进行赋值
{
for (int i = L; i <= R; i++)rk[i] = rak + i - L;
return;
}
dfs(l[n], L, n, rak + (p[n] % 10 > d[n]) * (R - n));
dfs(r[n], n + 1, R, rak + ((p[n] % 10 < d[n]) * (n - L + 1)));
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
scanf("%d", &n);
ll pseed, pa, pb, pmod, dseed, da, db, dmod;
scanf("%lld%lld%lld%lld%lld%lld%lld%lld", &pseed, &pa, &pb, &pmod, &dseed, &da, &db, &dmod);
for (int i = 0; i < n; i++)//构造p
{
p[i] = i;
}
ll seed = dseed;
for (int i = 0; i < n; i++)
{
d[i] = seed % 10;
seed = (seed * da + db) % dmod;
}
seed = pseed;
for (int i = 1; i < n; i++)
{
swap(p[seed % (i + 1)], p[i]);
seed = (seed * pa + pb) % pmod;
}
for (int i = 0; i < n; i++)
{
if (p[i] % 10 == d[i])p[i] = inf;//如果p[i]位置的字符就是d[i]的话,此次修改无意义,赋值p[i]为极大值
}
Cartesian(n);
memset(rk, 0, sizeof(int) * (n + 1));
dfs(st[1], 0, n, 0);
ll ans = 0, tmp = 1;
for (int i = 0; i <= n; i++)
{
ans = (ans + (ll)rk[i] * tmp % mod) % mod;
tmp *= 10000019LL;
tmp %= mod;
}
printf("%lld\n", ans);
}
return 0;
}
L.Problem L is the Only Lovely Problem(签到)
题目描述
给一个字符串,判断开头六个字符是不是 \(lovely\)(不区分大小写)。
分析
签到。
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
string str;
cin >> str;
for (int i = 0; i < str.size(); i++)
{
str[i] = tolower(str[i]);
}
if (str.substr(0, 6) == "lovely")puts("lovely");
else puts("ugly");
return 0;
}