牛客月赛46【部分题解】

题单地址:https://ac.nowcoder.com/acm/contest/11223
打的贼烂,赛后就补前四题,后两道懒得搞了。

赢的次数【签到】

在这里插入图片描述
一共n场,对于每一场只有输赢。故总状态2^n 设赢k场故从n中选k。
故对半分最大。

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    
    
	int n; cin>>n;
	if(n%2==0) cout<<n/2;
	else cout<<n/2<<" "<<n/2+1;
	return 0;
}

子段和【构造】

在这里插入图片描述
有0,直接输出NO,只有俩值,且这俩值和为0也输出NO。
其余为0。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
int n,a[N];
map<int,int>mp;
int main(void)
{
    
    
	cin>>n;
    bool flag=1;
	for(int i=1;i<=n;i++) 
    {
    
      
        cin>>a[i],mp[a[i]]++;
        if(!a[i]) flag=0;
    }
    sort(a+1,a+n+1);
    if(mp.size()==2&&a[1]+a[n]==0) flag=0;
    if(!flag) puts("NO");
    else puts("YES");
	return 0;
}

英语作文【双指针】

在这里插入图片描述
双指针来维护区间,累加。

#include<bits/stdc++.h>
using namespace std;
int n,m;
map<string,int>mp;
string s,ss;
vector<string>ve;
int main(void)
{
    
    
	cin>>n>>m;
	getline(cin,s),getline(cin,s);
	stringstream l(s);
	while(l>>ss) ve.push_back(ss);
	long long int ans=0;
	for(int i=0,j=0;i<ve.size();i++)
	{
    
    
		while(i-j-1>m) mp[ve[j]]--,j++;
		ans+=mp[ve[i]];
		mp[ve[i]]++;
	}
	cout<<ans;
	return 0;
}

主席树写法,区间查找x出现的次数。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=200010;
int n,m,root[MAXN],cut,a[MAXN],s[MAXN];
struct data
{
    
    
    int lc,rc,ans;
}tree[MAXN*20];
void add(int &now,int last,int l,int r,int x)
{
    
    
    now=++cut;
    tree[now].ans=tree[last].ans+1;

    if(l==r) return ;
    tree[now].lc=tree[last].lc;
    tree[now].rc=tree[last].rc;
    int mid=(l+r)>>1;
    if(x<=mid) add(tree[now].lc,tree[last].lc,l,mid,x);
    else add(tree[now].rc,tree[last].rc,mid+1,r,x);
}
int query(int L,int R,int l,int r,int x)
{
    
    
    if(l==r)return tree[L].ans-tree[R].ans;
    int mid=(l+r)>>1;
    if(x<=mid)return query(tree[L].lc,tree[R].lc,l,mid,x);
    else return query(tree[L].rc,tree[R].rc,mid+1,r,x);
}
int main()
{
    
    
    int p=0;
    scanf("%d%d",&n,&m);
    string s1,ss; 
    getline(cin,s1);
    getline(cin,s1);
    stringstream l(s1);
    vector<string>ve;
    while(l>>ss) ve.push_back(ss);
    int idx=1;
    map<string,int>mp;
    for(int i=0;i<ve.size();i++)//离散化
    {
    
    
        if(mp[ve[i]]) a[i+1]=mp[ve[i]];
        else
        {
    
    
            a[i+1]=idx;
            mp[ve[i]]=idx;
            idx++;
        }
    }
    for(int i=1;i<=n;++i) p=max(p,a[i]);
    for(int i=1;i<=n;++i)
        add(root[i],root[i-1],1,p,a[i]);
    long long int ans=0;
    for(int i=1;i<=n;i++)
    {
    
    
        int x=i+1,y=min(i+m+1,n);//查找区间内单词出现的次数
        ans+=query(root[y],root[x-1],1,p,a[i]);
    }
    cout<<ans;
    return 0;
}

生活在树上【思维】

在这里插入图片描述
对于一个根节点,只有边长为2和边长为1这两种情况。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10; 
vector<int>ve[N][3];
void add(int a,int b,int c)
{
    
    
	if(c>2) return;
	ve[a][c].push_back(b);
	ve[b][c].push_back(a);
}
int main(void)
{
    
    
	int n; cin>>n;
	for(int i=2;i<=n;i++)
	{
    
    
		int a,b; scanf("%d%d",&a,&b);
		add(i,a,b);
	}
	for(int i=1;i<=n;i++)
	{
    
    
		int ans=ve[i][2].size()+1;//边长为2的点的个数+本身
		for(int j=0;j<ve[i][1].size();j++) 
		{
    
    
		    int u=ve[i][1][j];//儿子的边长为1的树的点的个数
		    ans+=ve[u][1].size();
		}
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46527915/article/details/123748266