Codeforces Round #668 (Div. 2)
A.Permutation Forgery
题意:给一个数组p,找到另一个数组,使数组中相邻元素相加构成的新数组元素相同。
思路:将数组反着输出。
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll t,n,a[1005];
int main()
{
scanf("%lld",&t);
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=n;i>=1;i--)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
}
B.Array Cancellation
题意:给一个和为0的数组,每次可选择(a_i)-1和(a_j)+1,若i<j花费为0,否则花费为1,求所有数变为0的花费。
思路:用num存所有数绝对值之和,sum存目前位置可用来与负数免费运算的值,ans存进行免费运算的值。因为每次都是2个数同时运算,所以答案为(num-ans$*$2)/2。
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll t,n,sum,a[100005],num,x,ans,s;
int main()
{
scanf("%lld",&t);
while(t--)
{
sum=0;ans=0;x=0;num=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]>0)
{
sum=sum+a[i];
num+=a[i];
}
if(sum>0&&a[i]<0)
{
num-=a[i];
s=-a[i];
x=min(sum,s);
sum=sum-x;
ans=ans+x;
}
else if(a[i]<0)
{
num-=a[i];
}
}
cout<<(num-2*ans)/2<<endl;
}
}
C.Balanced Bitstring
题意:给一个二进制字符串,其中?能为0或1,问是否能使任意长度为k的字串0,1数量相同。
思路:首先判断同余字符是否相同,不同则输出NO。用a[0]--a[k-1]存储同余位置的字符,若未确定(同余位置全是?)为0,若字符为'0'为1,若字符为'1'为2。再遍历一边字符串,若str[i]为'?',其同余数组a不为0,说明?可以确定,则?变为相应的字符串。遍历同余数组a,若没有a[i]为0,则判断为1和为2数量是否相同,相同YES,反之NO。若有a[i]为0,则为1和为2数量之差小于等于为数量,说明?肯定有一种分配可以使字符串0,1数量相等,则YES,反之则NO。
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
ll t,n,k,a[300005],flag,b[2],sum,len,sum1,sum2;
//string str;
char str[300005];
int main()
{
scanf("%lld",&t);
while(t--)
{
memset(a,0,sizeof(a));
flag=0;
scanf("%lld%lld",&n,&k);
//cin>>str;
scanf("%s",str);
len=strlen(str);
for(int i=0;i<len;i++)
{
if(str[i]=='?')
{
continue;
}
else if(a[(i+1)%k]==0)
{
a[(i+1)%k]=str[i]-'0'+1;
}
else if(a[(i+1)%k]!=0)
{
if((str[i]-'0'+1)!=a[(i+1)%k])
{
flag=1;
printf("NO
");
break;
}
}
}
if(flag==0)
{
for(int i=0;i<len;i++)
{
if(str[i]=='?')
{
if(a[(i+1)%k]!=0)
{
str[i]=a[(i+1)%k]-1+'0';
}
}
}
sum=0;sum1=0;sum2=0;
for(int i=0;i<k;i++)
{
if(a[i]==0)
sum++;
if(a[i]==1)
sum1++;
if(a[i]==2)
sum2++;
}
if(sum)
{
if(abs(sum1-sum2)>sum)
{
flag=1;
printf("NO
");
}
}
else if(sum1!=sum2)
{
flag=1;
printf("NO
");
}
}
if(flag==0)
printf("YES
");
}
}
D.Tree Tag
题意:在一颗n个顶点的树上,Alice在a点,Bob在b点,Alice每次可走最多da步,Bob每次最多db步,Alice先走,若无限步内Alice和Bob可占据(每一步的起始,结束点为占据)同个点,Alice胜,反之Bob胜。
思路:Alice获胜有3种可能。
1.Alice一步抓到Bob,即da>(D_{ab}),用dfs计算ab距离 (D_{ab})。
2.2(*)da>(D_{tree}) ,即Alice站在树的直径中点可到达树的任何一点。用dfs1算出树的直径。
3.db<2da,即BOb被Alice一直追到极限处,无法越过Alice反向逃跑。
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimize ("unroll-loops")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<iostream>
#define INF 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int t,n,a,b,da,db,ans,mmax,x,flag;
struct node
{
int v;
int next;
}s[200005];
int first[400005],cnt,vis[200005];
void init()
{
memset(first,0,sizeof(first));
memset(vis,0,sizeof(vis));
cnt=1;flag=0;
}
void add(int u,int v)
{
s[cnt].v=v;
s[cnt].next=first[u];
first[u]=cnt++;
}
void dfs(int u,int sum)//计算a,b间距离
{
vis[u]=1;
for(int i=first[u];i;i=s[i].next)
{
int v=s[i].v;
if(vis[v])
continue;
if(v==b)
{
ans=sum+1;
flag=1;
return;
}
dfs(v,sum+1);
if(flag==1)
return;
}
}
void dfs1(int u,int sum)
{
vis[u]=1;
for(int i=first[u];i;i=s[i].next)
{
int v=s[i].v;
if(vis[v])
continue;
dfs1(v,sum+1);
}
if(sum>mmax)
{
mmax=sum;
x=u;
}
}
int main()
{
int u,v;
scanf("%d",&t);
while(t--)
{
cin>>n>>a>>b>>da>>db;
init();
for(int i=1;i<n;i++)
{
cin>>u>>v;
add(u,v);add(v,u);
}
ans=0;//记录a,b间距离
dfs(a,0);
if(ans<=da)
{
cout<<"Alice"<<endl;
continue;
}
for(int i=1;i<=n;i++)
vis[i]=0;
mmax=0;
dfs1(1,0);//找到直径的一个端点
for(int i=1;i<=n;i++)
vis[i]=0;
mmax=0;
dfs1(x,1);//算出直径的长度
if(da<mmax/2&&db>da*2)
cout<<"Bob"<<endl;
else
cout<<"Alice"<<endl;
}
}
E.Fixed Point Removal
题意:给一个数列a,若a[i]==i则可以删除,删除后左右部分连接。询问q(x,y),前x个,后y个元素变为n+1,问每次询问能删几个数。
思路:首先,进行转换a[i]=i-a[i];则a[i]的含义变为i位置左边若能删除a[i]个元素,则a[i]可以删除。
若f(l,r)表示[l,r]区间最多能删除的数的个数,则(f[l][r]=f[l][r-1]+1(0<=a[r]<=f[l][r-1])),若a[i]不满足则(f[l][r]=f[l][r-1])。因为f(l,r)对于相同的r具有单调性,所以我们每次可以在树状数组上二分找点。(代码网上找的...)
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 300010
int n,m,a[maxn];
struct TREE{
int tr[maxn];
void add(int x){for(;x<=n;x+=(x&-x))tr[x]++;}
int sum(int x){int re=0;for(;x;x-=(x&-x))re+=tr[x];return re;}
}tr;
struct par{int x,pos;};
vector<par>q[maxn];
int ans[maxn];
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]=i-a[i];
for(int i=1,x,y;i<=m;i++)scanf("%d %d",&x,&y),q[n-y].push_back((par){1+x,i});
for(int i=1;i<=n;i++){
if(a[i]>=0){
int l=1,r=i,p=-1;
while(l<=r){
int mid=l+r>>1;
if(tr.sum(i)-tr.sum(mid-1)>=a[i])p=mid,l=mid+1;
else r=mid-1;
}
if(p!=-1)tr.add(p);
}
for(par j:q[i]){
ans[j.pos]=tr.sum(i)-tr.sum(j.x-1);
}
}
for(int i=1;i<=m;i++)printf("%d
",ans[i]);
}