2021牛客寒假算法基础集训营4

A九峰与签到题

签到题,然而wa5。保证任意时刻的都大于等于50%,才能算做签到题。

#include <bits/stdc++.h>
#define pb push_back//vector,deque
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e5+5;
void solve()
{
    int t;
    cin>>t;
    while(t--){

    }
}
struct node{
    int ac,fail,success,submit;
}a[25];
int main() {
    //solve();
    int n,m,x;
    string op;
    cin>>m>>n;
    for(int i=0;i<m;i++){
        cin>>x>>op;
        if(op=="AC")a[x].ac++;
        else a[x].fail++;
        a[x].submit=1;
        double score=1.0*a[x].ac/(1.0*a[x].ac+1.0*a[x].fail);
        if(score>=0.5){
            a[x].success++;
        }
    }
    bool flag=false;
    for(int i=1;i<=n;i++){
        if(a[i].submit==0){
            continue;
        }
        if(a[i].success==a[i].ac+a[i].fail){
            cout<<i<<' ';flag=true;
        }
    }
    if(!flag)cout<<"-1";
    cout<<"\n";
    return 0;
}

/*
3 2
1 AC
1 UNAC
1 UNAC
*/ 

B武辰延的字符串

给你两个串s和t。对于字符串前缀si+sj= t i + j t_{i+j} ti+j。寻找有多少个这样的组合。


暴力做法就是枚举si,再枚举sj然后去 t i + j t_{i+j} ti+j判断合法。首先判断两个字符串是否相等可以降低到O(1),就是用字符串哈希。然后分析时间复杂度 O ( n 2 ) O(n^2) O(n2)。肯定超时。

换一种思路:实际上我们枚举si时,只需要找到s串和从 t i + 1 t_{i+1} ti+1开始的最长公共前缀就能贡献答案(贡献答案就是si后面的长度)那么我们可以通过二分来寻找最大公共前缀。二分s的长度然后通过哈希与 t i + 1 t_{i+1} ti+1~ t i + 1 + m i d t_{i+1+mid} ti+1+mid之间字符串判断即可。

#include <bits/stdc++.h>
#define pb push_back//vector,deque
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e5+5,mod=1e9+7;
string s,t;
int p=233;//10不行 
ll hasha[N],hashb[N];
void hash_(string str,ll a[])
{
	a[0]=str[0]-'a';
	int n=str.size();
	for(int i=1;i<n;i++){
		a[i]=(a[i-1]*p+str[i]-'a')%mod;
	}
}
ll q_pow(ll a,ll b)
{
	ll res=1;
	while(b){
		if(b&1)res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
} 
ll calhash(ll a[],int l,int r)
{
	if(l==0)return a[r];
	else return ((a[r]-a[l-1]*q_pow(p,r-l+1)%mod)%mod+mod)%mod;
}
int main() {
	cin>>s>>t;
	hash_(s,hasha);
	hash_(t,hashb);
	ll res=0;
	int lens=s.size(),lent=t.size();
	for(int i=0;i<lens;i++){
//		if(s[i]!=t[i])break;
		if(hasha[i]!=hashb[i])break;
		int l=0,r=lens-1,temp=-1;
		while(l<=r){
			int mid=l+r >>1;
			ll ls=hasha[mid],lt;
			if(i+1+mid>=lent)lt=-1;
			else lt=calhash(hashb,i+1,i+1+mid);
			if(ls==lt){
				temp=mid;l=mid+1;
			}else r=mid-1;
		}
		if(temp!=-1)res+=temp+1;
	}
	cout<<res<<'\n';
    return 0;
}

J邬澄瑶的公约数

这道题就是求一些数的gcd。首先线筛把质数筛出来,然后对其分解质因数。实际上这里的 x i , p i x_i,p_i xi,pi需要分解成 ( 2 a 1 ∗ 3 a 2 ∗ . . . ∗ p n a n ) p i (2^{a1}*3^{a2}*...*pn^{an})^{p^i} (2a13a2...pnan)pi。分解里面的最后cot*pi求最小即可。这里的vis2是为了保证求所有数都出现质数,然后才能放到答案里


#include <bits/stdc++.h>
#define pb push_back//vector,deque
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e4+5;
ll mod=1e9+7;
int  X[N],Y[N],prime[N],vis[N],vis2[N];
void solve()
{
    int t;
    cin>>t;
    while(t--){

    }
}
ll q_pow(ll a,ll b)
{
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
void get_prime(int n)
{
    for(int i=2;i<=n;i++){
        if(!vis[i])prime[++prime[0]]=i;
        for(int j=1;j<=prime[0]&&i*prime[j]<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
int main() {
    //solve();
    int n,maxx=0;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>X[i];
    }
    for(int i=0;i<n;i++)cin>>Y[i];
    map<int,int>mp;
    get_prime(10005);
    for(int i=0;i<n;i++){
        int x=X[i],p=Y[i];
        if(!vis[x]){
			if(mp.find(x)==mp.end()){
                mp[x]=p;vis2[x]++;
            }else {
				mp[x]=min(mp[x],p);vis2[x]++;
			}
			continue;
		}
        for(int j=1;j<=prime[0];j++){
            int cot=0;
            if(x%prime[j]==0){
                while(x%prime[j]==0){
                    cot++;x/=prime[j];
                }
                if(mp.find(prime[j])==mp.end()){
	                mp[prime[j]]=cot*p;vis2[prime[j]]++;
	            }else {
					mp[prime[j]]=min(mp[prime[j]],cot*p);vis2[prime[j]]++;
				}
            }
        }
        if(x>1){
				mp[x]=1;vis2[x]++;
        }
    }
    ll res=1;
    for(auto it:mp){
        ll x=it.first,p=it.second;
//        cout<<x<<' '<<p<<' '<<vis2[x]<<'\n';
		if(vis2[x]==n)
        res=res*q_pow(x,p)%mod;
    }
    cout<<res<<'\n';
    //cout<<gcd(4,6);
    return 0;
}
/*
3
9 3 6
1 2 3
27

5
1236 218 124 326 182
2231 823 215 214 325
908002374

2
2 4
2 2
*/

H吴楚月的表达式

求一棵树上的表达式。


因为涉及到±*/必然有优先级的考虑。求的是每个节点的表达式。所以我们在遍历树的时候不能只算该节点的结果。还需要考虑后面的影响。比如2+3*5。第一个节点2,第二个节点res=2+3=5。但是第三个节点不能从第二个节点推出来了。res=5*5,这个是错的。所以必须考虑乘除的优先级。对每个节点不妨设他的计算形式a+b形式的(其中b是为了后边便于乘所需要的维护的)。这样我们每次维护这种就可以考虑到优先级。比如样例。对于1节点的权值3。维护该节点{a=0,b=3}。

如果下一个节点是+,那么{a2=a1+b1,b2=node[2]}(node[i]是第i个节点的权值)

如果下一个节点是-,那么{a2=a1+b1,b2=(-node[2]+mod)%mod}(该题对res%mod,这里防止负数)

如果下一个节点是* ,那么{a2=a1,b2=b1*node[2]}

如果下一个节点是/,那么{a2=a1,b2=b1*q_pow(node[2],mod-2)}(除法需要用到逆元)

综上:对于每个节点res=resa[i]+resb[i]即可。就是a+b的形式

#include <bits/stdc++.h>
#define pb push_back//vector,deque
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e5+5,mod=1e9+7;
int node[N],fa[N];
ll resa[N],resb[N];
vector<pair<int,char>>e[N];
string op;
void solve()
{
    int t;
    cin>>t;
    while(t--){

    }
}
ll q_pow(ll a,ll b)
{
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
void fun(int u,int fa,char opp)
{
    if(opp=='+'){
    	resa[u]=(resa[fa]+resb[fa])%mod;
    	resb[u]=node[u]%mod;
    }else if(opp=='-'){
        resa[u]=(resa[fa]+resb[fa])%mod;
        resb[u]=(-node[u]%mod+mod)%mod;
    }else if(opp=='*'){
    	resa[u]=resa[fa];
    	resb[u]=resb[fa]*node[u]%mod;
    }else if(opp=='/'){
    	resa[u]=resa[fa];
    	resb[u]=(resb[fa]*q_pow(node[u],mod-2)%mod)%mod;
    }
}
void dfs(int u,int fa,char opp)
{
    if(u!=1){
        fun(u,fa,opp);
    }
    for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i].first;
        char opp=e[u][i].second;
        if(v==fa)continue;
        dfs(v,u,opp);
    }
    return ;
}
int main() {
    // solve();
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>node[i];
    for(int i=1;i<=n-1;i++)cin>>fa[i];
    cin>>op;
    for(int i=1;i<=n-1;i++){
        int u=fa[i],v=i+1;
        char opp=op[i-1];
        // e[v].push_back(u);
        e[u].push_back({v,opp});
    }
    resa[1]=0,resb[1]=node[1];
    dfs(1,-1,'-');
    for(int i=1;i<=n;i++){
        if(i>1)cout<<' ';
        cout<<(resa[i]+resb[i])%mod;
    }
    cout<<'\n';
    return 0;
}
/*
6
3 4 2 2 3 5
1 1 3 4 5
/*-**
3 750000006 6 4 0 999999983
*/

猜你喜欢

转载自blog.csdn.net/qq_43566782/article/details/113924834