2020牛客暑期多校训练营(第四场)

总结:
出了两道题,添老师开始看错F题的题意了,WA了一发,后面又A了。B题看出了题意,实现的时候细节有问题,后面添老师和lyx一起解决了。

B

题意

由于是每次都是ccc…所以不用看c了,直接分解n
要想max最大,很明显需要尽量多次得分解n,那么每次找n的最大因子x,gcd(n,x)

思路

在打素数筛时加个贡献就可以。然后快速幂求解。

代码

#include<iostream>
#include<cmath>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <complex>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cassert>
using namespace std;
typedef long long ll;
const ll inf =1e17;
#define scn(a) scanf("%d",&a)
#define scd(a) scanf("%lf",&a)
#define scl(a) scanf("%lld",&a)
#define ptf(a) printf("%d\n",a)
#define mes(a,b) memset(a,b,sizeof(a))
#define fon(s,n) for(int i=s;i<=n;i++)
#define range(i,a,b) for(int i=a;i<=b;++i)
#define rerange(i,a,b) for(int i=a;i>=b;--i)
//#define N 100010
//const ll p =998244353;
const int S=20;
ll gcd(ll a,ll b) { return b>0 ? gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a*b/gcd(a,b);}
ll q_pow(ll a,ll b,ll mod)
{
    ll ans=1,res=a;
    while(b){
        if(b&1) ans=ans*res%mod;
        res=res*res%mod;
        b>>=1;
    }
    return ans%mod;
}
 
#define maxn 1000010
bool vis[maxn];
ll prime[maxn],x;
ll cnt[maxn]={0};
void isprime(int n) //埃氏筛
{
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]) prime[x++]=i;
        for(int j=2;j*i<=n;j++)
        {
            vis[i*j]=true;
        }
    }
}
void count(){
    for(int i=2;i<=maxn;i++){
        int temp=i;
        int re=1;
        for(int j=0;j<x&&vis[temp];j++){
             while(temp%prime[j]==0&&vis[temp]){
                re++;
                temp/=prime[j];
            }
        }
        cnt[i]=re;
    }
}
 
const ll mp=1e9+7;
int main() 
{ 
    int t,n;
    ll c;
    isprime(1000005);
    count();
    scn(t);
    while(t--){
        scn(n);scl(c);
        ll ans;
        //if(n==1) ans=c%mp;
        //else
            ans=q_pow(c,cnt[n],mp);
        printf("%lld\n",ans);
    }
    return 0; 
}

C

题意

SS的|S||S|个后缀进行ff操作,求这|S|个操作后的后缀的本质不同的子串个数

思路

把每个操作后的后缀翻转后插入字典树
当所有后缀都插入字典树之后建广义后缀自动机
直接统计答案即可代码

代码

#include<bit s/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e6+10;
char s[maxn], t[maxn], rec[maxn];

struct Trie
{
int O, c[maxn], fa[maxn], tr[maxn][10];
int pos[maxn];

Trie()
{
O = 1;
}
void insert(int k, char ch[], int id)
{
int p = id;
for (int i = 1; ch[i]; ++i)
{
int rec = ch[i] - 'a';
if (!tr[p][rec])tr[p][rec] = ++O, fa[O] = p, c[O] = rec;
p = tr[p][rec];
}
pos[k] = p;
}
}T1;

struct Suffix_Automaton
{
int O, pos[maxn], link[maxn], len[maxn], trans[maxn][10];
queue<int> Q;
Suffix_Automaton()
{
O = 1;
}
int insert(int ch, int last)
{
int x, y, z = ++O, p = last;
len[z] = len[last] + 1;
while (p && !trans[p][ch])trans[p][ch] = z, p = link[p];
if (!p)link[z] = 1;
else {
x = trans[p][ch];
if (len[p] + 1 == len[x])link[z] = x;
else {
y = ++O;
len[y] = len[p] + 1;
for (int i = 0; i < 10; ++i)trans[y][i] = trans[x][i];
while (p && trans[p][ch] == x)trans[p][ch] = y, p = link[p];
link[y] = link[x], link[z] = link[x] = y;
}
}
return z;
}

void build()
{
for (int i = 0; i < 10; ++i)if (T1.tr[1][i])Q.push(T1.tr[1][i]);
pos[1] = 1;
while (!Q.empty()) {
int x = Q.front();
Q.pop();
pos[x] = insert(T1.c[x], pos[T1.fa[x]]);
for (int i = 0; i < 10; ++i)if (T1.tr[x][i])Q.push(T1.tr[x][i]);
}
}

void solve()
{
ll ans = 0;
for (int i = 2; i <= O; ++i)ans += len[i] - len[link[i]];
printf("%lld\n", ans);
}
} SAM;

int main()
{
scanf("%s",s+1);
int n=strlen(s+1);
int len=0;int cnt=0;
t[++len]=s[n];
T1.pos[n+1]=1;
T1.insert(n,t,1);
for(int i=n-1;i;i--)
{
cnt=0;
rec[++cnt]=s[i];
int k=i+1;
for(int j=len;j>=1;j--)
{
if(s[i]<=t[j]) break;
if(s[i]>t[j])
{
t[j]=s[i];
rec[++cnt]=s[i];
++k;
}
}
rec[cnt+1]='\0';
T1.insert(i,rec,T1.pos[k]);
t[++len]=s[i];
}
SAM.build();
SAM.solve();
return 0;
}


F

题意

如图,给出AC,AD,BC,BD的长度,让你判断是AB||CD,还是AB||DC(这里的AB||CD指的是如下左图的情况)。

在这里插入图片描述

思路

因为给的是边,所以一直在考虑边的解法,但是因为自己太菜一直没想明白,最后还是像个憨憨算了余弦值才判断出来的,下来看题解才发现原来只需要判断边长就可以了,还有更神仙的大佬把想成梯形,然后我们都知道梯形的对角线之和要大于两腰之和,然后几行代码就过了。

在这里插入图片描述

代码

#include<bits/stdc++.h>//自己的
using namespace std;
int main(){
	int te;
	cin>>te;
	while(te--){
		int a,b,c,d;
		bool f=1;
		cin>>a>>b>>c>>d;
		int q=min(a,min(b,min(c,d)));
			if(q==a){
				int x=c*c-a*a;
				int xx=(x+b*b-d*d);
				if(xx>0) {
					puts("AB//CD");
					continue;
				}
				else {
					puts("AB//DC");
					continue;
				}
			}
			else if(q==b){
				int x=d*d-b*b;
				int xx=(x+a*a-c*c);
				if(xx>0) {
					puts("AB//DC");
					continue;
				}
				else {
					puts("AB//CD");
					continue;
				}
				}			
			else if(q==c){
				int x=a*a-c*c;
				int xx=(x+d*d-b*b);
				if(xx>0) {
					puts("AB//DC");
					continue;
				}
				else {
					puts("AB//CD");
					continue;
				}
			}
			else if(q==d){
				int x=b*b-d*d;
				int xx=(x+c*c-a*a);
				if(xx>0) {
					puts("AB//CD");
					continue;
				}
				else {
					puts("AB//DC");
					continue;
				}
			}
	}
	return 0;
}

#include<bits/stdc++.h>//大佬的
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        puts(b+c>a+d?"AB//CD":"AB//DC");
    }
    return 0;
}

H

题意

给出n,在1-n中,选出最多的匹配对数,使得每对数互质。

思路

除了1,小于n/2的数一定有匹配的数。将1-N不是质数的数用数组存起来。由大到小遍历,1-n/2范围内的质数,如果已配对数字,进入下个循环,若没有配对,以pos记录下标,继续寻找可以与其配对的数,找到可配对的数后,计数加1,a[j]=pos,a[pos]=j,用a数组记录配对坐标,初始化pos=0。

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false),cin.tie(0);
#define ll long long
#define inf 0x3f3f3f3f
const int N=2e5+5;
//set<string>b;
//set<string>::iterator it;
int a[N],vis[N];
void init()
{
	int i,j;
	for(i=2;i<=N;i++)
	{
		if(!vis[i])
		{
			for(j=2*i;j<=N;j+=i)
			{
				vis[j]=1;
			}
		}
	}
}
int main()
{
    IO;
    init();
    int T,n,i,j,pos,ans;
    cin>>T;
    while(T--)
    {
    	pos=0;ans=0;
		cin>>n;
    	for(i=1;i<=n;i++) a[i]=0;
    	for(i=n/2;i>=2;i--)
    	{
    		if(!vis[i])
    		{
    			pos=i;
    			for(j=n/i*i;j>i;j-=i)
    			{
    				if(a[j]) continue;
    				if(pos==0) pos=j;
    				else
    				{
    					ans++;
    					a[j]=pos;
    					a[pos]=j;
    					pos=0;
					}
				}
			}
		}
		cout<<ans<<endl;
		for(i=2;i<=n;i++)
		{
			if(a[i]>i) cout<<i<<" "<<a[i]<<endl;
		}
	}
    return 0; 
}


一级目录

题意

思路

代码

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页