题目链接
本人比较的菜,D题是比赛结束后十分钟才把代码打完~ E,F不会~
A. Shuffle Hashing
A题暴力即可
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e3+10;
char s[N],t[N];
int main()
{
int _;cin>>_;while(_--)
{
scanf("%s%s",s+1,t+1);
int n=strlen(s+1);
int m=strlen(t+1);
int f=1;
int vis[30],vs[30];
for(int i=0;i<26;++i) vis[i]=0,vs[i]=0;
for(int i=1;i<=n;++i) vis[s[i]-'a']++;
for(int i=1;i+n-1<=m&&f;++i){
for(int i=0;i<26;++i) vs[i]=0;
for(int j=i;j<=i+n-1;++j){
vs[t[j]-'a']++;
}
bool flag=1;
for(int j=0;j<26&&flag;++j){
if(vs[j]!=vis[j]) {
flag=0;
//printf("j:%d\n",j);
}
}
if(flag) f=0;
}
if(!f) puts("YES");
else puts("NO");
}
}
B. A and B
假设a
先将1,2,3,4,一直加到小的一部分。。。然后当 a>b 的时候,(a-b)%2==0 的时候,就在1,2,3,4.。。。中选一个偶数分给b即可。。。
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
ll a,b;
ll dp[N],num[N];
int main()
{
int _;cin>>_;while(_--)
{
scanf("%lld%lld",&a,&b);
if(a==b){
puts("0");
continue;
}
if(a
C. Berry Jam
设x是红色的个数,y是白色的个数
遍历一遍 前缀记录x-y,用map记录位置即可。。
后缀遍历计算x-y,在map中通过找-(x-y) 得到合法区间即可。。
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
int dp[N][3],f[N][3],n,a[N],b[N];
int main()
{
int _;cin>>_;while(_--)
{
scanf("%d",&n);
mapmp;
n=2*n;
int x=0,y=0;
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
}
int ans=n;
rep(i,1,n/2)
{
if(a[i]==1) x++;
else y++;
if(x==y) ans=min(ans,n-i);
mp[x-y]=i;
}
x=0,y=0;
for(int i=n;i>=n/2+1;--i){
if(a[i]==1) x++;
else y++;
if(x==y) ans=min(ans,i-1);
if(mp[-(x-y)]!=0) ans=min(ans,i-mp[-(x-y)]-1);
}
printf("%d\n",ans);
}
}
D. Segment Tree
做法1:线段树(已被HACK)
hack数据:
5
1 4
2 5
3 6
7 9
8 10 求联通块有问题
树的特点:边数=n-1,然后是一个联通块。。
连通块好计算,一层for求区间并即可
边数怎么求呢?
从前往后遍历,遇到左区间,就线段树上点更新,遇到右区间就查询区间和,就是边数。。
我写了两颗线段树(正着一遍 反着一遍)来判断是否有独立的点,感觉没必要,写多了(有求连通块就可以了)。
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
int n,vis[N],vs[N];
pi a[N],b[N];
ll sum[N*4],s[N*4];
void up(int id,int l,int r,int pos,int val,int ty)
{
if(l==r) {
if(ty) sum[id]+=val;
else s[id]+=val;
return ;
}
int mid=l+r>>1;
if(pos<=mid) up(id<<1,l,mid,pos,val,ty);
else up(id<<1|1,mid+1,r,pos,val,ty);
if(ty) sum[id]=sum[id<<1]+sum[id<<1|1];
else
s[id]=s[id<<1]+s[id<<1|1];
}
ll qu(int id,int l,int r,int ql,int qr,int ty)
{
if(ql<=l&&r<=qr){
if(ty)
return sum[id];
else return s[id];
}
ll res=0;
int mid=l+r>>1;
if(ql<=mid) res+=qu(id<<1,l,mid,ql,qr,ty);
if(qr>mid) res+=qu(id<<1|1,mid+1,r,ql,qr,ty);
return res;
}
int main()
{
cin>>n;
for(int i=1;i<=n;++i){
scanf("%d%d",&a[i].first,&a[i].second);
b[i].first=a[i].first;
b[i].second=a[i].second;
vis[a[i].first]=i;
vis[a[i].second]=i;
}
if(n==1){
puts("YES");
return 0;
}
sort(b+1,b+1+n);
int flag=1;
int l=b[1].first,r=b[1].second;
for(int i=1;i<=n&&flag;++i){
bool tmp=0;
if(b[i].first<=r) tmp=1;
l=min(l,b[i].first);
r=max(r,b[i].second);
if(!tmp) flag=0;
}
if(!flag){
puts("NO");
return 0;
}
ll ans=0;
for(int i=2*n;i>=1;--i){
int id=vis[i];
if(a[id].second==i){
up(1,1,2*n,a[id].second,1,1);
}
else{
ll t;
t=qu(1,1,2*n,a[id].first,a[id].second,1)-1;
up(1,1,2*n,a[id].second,-1,1);
if(t>0) ans+=t,vs[id]=1;
}
}
for(int i=1;i<=2*n;++i){
int id=vis[i];
if(a[id].first==i){
up(1,1,2*n,a[id].first,1,0);
}
else{
ll t;
t=qu(1,1,2*n,a[id].first,a[id].second,0)-1;
up(1,1,2*n,a[id].first,-1,0);
if(t>0) vs[id]=1;
}
}
int f=1;
for(int i=1;i<=n&&f;++i) if(vs[i]==0) f=0;
if(f&&ans==n-1) puts("YES");
else puts("NO");
}
做法2:
线段树求联通块有问题,那么就换种方式,开始想的是如何在线段树节点上保存所有区间内的区间标号。。
看了别人的代码,就是用set
#include
using namespace std;
#define pi pair
typedef long long ll;
const int N=1e6+10;
pi a[N];
int fa[N];
setst;
int n;
int fin(int x)
{
if(fa[x]!=x) fa[x]=fin(fa[x]);
return fa[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d",&a[i].first,&a[i].second);
fa[i]=i;
}
sort(a+1,a+1+n);
int f=1;
ll ans=0;
for(int i=1;i<=n&&f;++i){
auto l=st.lower_bound(make_pair(a[i].first,0));
auto r=st.lower_bound(make_pair(a[i].second,0));
for(auto it=l;it!=r&&f;++it){
int f1=fin(i);
int f2=fin((*it).second);
if(f1==f2) f=0;
else{
fa[f1]=f2;
ans++;
}
}
st.insert(make_pair(a[i].second,i));
}
if(f&&ans==n-1) puts("YES");
else puts("NO");
}
E. Tests for problem D
这题跟D题相反,现给你一颗树,能否构造一个D题一样的区间。。
有相交但不包含的区间就有一条边
l1 l2 r1 r2 代表着有一条边 ,l1 l2 r2 l1不算
做法:很妙的做法,看代码就懂了:
#include
using namespace std;
const int N=1e6+10;
vectorG[N];
int n,cnt,l[N],r[N];
void dfs(int u,int fa)
{
for(int v:G[u]){
if(v==fa) continue;
l[v]=++cnt;
}
r[u]=++cnt;
for(int i=G[u].size()-1;i>=0;--i){
if(G[u][i]==fa)continue;
dfs(G[u][i],u);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i