2020牛客暑期多校训练营(第三场)题解

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(1leq nleq 2 imes 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
",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|) 个字符放到字符串左边。

  数据范围:(2leq |S|leq 2 imes 10^6,1leq qleq 8 imes 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('
');
		}
		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(1leq nleq 50)) 个白点涂黑,使得有 (m(1leq mleq 200)) 对相邻的白点和黑点(相邻指曼哈顿距离为 (1))。

分析

  在平面上用小正方形构造一个可以分散的,面积为 (n),周长和为 (m) 的不规则图形。首先考虑 (n)(m) 的关系,显然,当 (n) 个小正方形互相不接触的时候是周长和最大的情况,此时 (m=4 imes n),当 (n) 个小正方形尽可能堆积成一个大正方形的时候,周长是最小的,此时 (m=2 imes(lceilsqrt{n} ceil+lceilfrac{n}{lceilsqrt{n} ceil} ceil)),另外,考虑对于每一个不规则图形的一条边,总存在另一条边与其对应,周长应该总是一个偶数,当 (m) 是奇数的时候同样无法构造答案。

  具体构造方法,可以认为一开始所有的小正方形都是排列在一条斜线上的,此时总周长是 (4 imes 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
", i, j);
				}
				/*putchar('
');*/
			}
			for (int i = 0; i < n; i++)
			{
				printf("%d %d
", i + 1000, i + 1000);
			}
		}
	}
	return 0;
}

E.Two Matchings(dp)

题目描述

  (p=[p_1,p_2,cdots,p_n]) 是一个长为 (n) 的全排列。

  定义一个全排列是一个 匹配,当且仅当 (forall i,p_i eq i 且 p_{p_i}=i)

  对于数组 (a=[a_1,a_2,cdots,a_n](0leq a_ileq 10^9,ngeq 4))(n) 是偶数,定义全排列的价值为 (frac{displaystylesum_{i=1}^{n}Big|a_i-a_{p_i}Big|}{2})

  定义两个 匹配 (p,q)可组合 的,当且仅当 (forall i,p_i eq q_i)

  找到两个 可组合匹配,使得这两个 匹配 的总价值尽可能小,输出价值之和。

  数据范围:(n) 的总和不超过 (2 imes 10^5,0leq a_ileq 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) 个数的次大 价值

  状态转移方程为:

[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]) ]

代码

#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
",ans+dp[n]);
    }
    return 0;
}

F.Fraction Construction Problem(exgcd+构造)

题目描述

  给出两个数字 (a,b(1leq a,bleq 2 imes 10^6)),求任意一组满足下列条件的 (c,d,e,f)

  • (frac{c}{d}-frac{e}{f}=frac{a}{b})

  • (d<b,f<b)

  • (1leq c,eleq 4 imes 10^{12})

  若无解,输出 (-1 -1 -1 -1)(1leq Tleq 10^5)

分析

  若 (gcd(a,b) eq 1) 时,令 (c=2a,d=b,e=a,f=b)

  若 (b=1),无解。

  若 (gcd(a,b)=1)

[frac{c}{d}-frac{e}{f}=frac{cf-de}{df}=frac{a}{b} ]

  令 (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 mid 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),则:

[frac{c}{d}-frac{e}{f}=frac{cf-ed}{df}=frac{a(c'p_1^{k_1}-e'p_1^{k_1-1}p_2^{k_2})}{p_1^{k_1-1}p_2^{k_2}p_1^{k_1}}=frac{ap_1^{k-1}}{p_1^{k_1-1}p_2^{k_2}p_1^{k_1}}=frac{a}{b} ]

代码

#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
",a*2,b,a,b);
            continue;
        }
        if(b==1)
        {
            printf("-1 -1 -1 -1
");
            continue;
        }
        gcd=b;
        while(gcd%fac[b]==0)
            gcd=gcd/fac[b];
        if(gcd==1)
        {
            printf("-1 -1 -1 -1
");
            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
",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)。最后输出每个点属于哪个团。

  数据范围:(2leq nleq 8 imes 10^5,1leq mleq 8 imes 10^5,1leq qleq 8 imes 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(1leq Tleq 10^3)) 组数据,首先输入 $n(1leq nleq 2 imes 10^6) $ 代表字符串长度以及需要构造的 (p)(d) 的长度,随后依次给出 (p_{seed},p_a,p_b,p_{mod}(0leq p_{seed},p_a,p_b<p_{mod}leq 10^9+7))(d_{seed},d_a,d_b,d_{mod}(0leq d_{seed},d_a,d_b< d_{mod}leq 10^9+7) 按照

[egin{aligned} &seed=P_{seed}\ &for i=0 to n -1:\ & p[i]=i\ &for i=1 to n-1:\ & swap(p[seed\%(i+1)],p[i])\ & seed=(seed*P_a+P_b)\%P_{mod}\ end{aligned} ]

的方式构造序列 (p),按照

[egin{aligned} &seed=d_{seed}\ &for i=0 to n-1\ & d[i]=seed\%10\ & seed=(seed*d_a+d_b)\%d_{mod} end{aligned} ]

的方式构造序列 (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
", 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;
}
原文地址:https://www.cnblogs.com/ResuscitatedHope/p/13775506.html