题单地址: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;
}