Codeforces Round #410 (Div. 2) 解题报告
2017-06-02 11:23
441 查看
A:Mike and palindrome
题意就是让你判断一个字符串最多修改一个字符后能不能成为一个回文串。。
所以只要判回文的时候记录一下有多少个不同的位置就行了
B:Mike and strings
不知道可不可以贪心,题意是给你n个字符串,然后你每次操作可以把一个字符串的第一个字符放到最后面,问最少多少次能让所有字符串一样
。。。反正直接枚举一个标准字符串, 然后模拟就行了
C:Mike and gcd problem
这题还是比较有意思的……
题意:给定一个序列A,每次操作可以选出其中两个数字x,y,删除,并且加入x+y,x-y两个数字,问最少多少次操作让序列的gcd>1
很显然的是,两个新加入的数字的gcd若不是1则必然是偶数,所以我们就贪心的认为尽可能把序列中所有的数字变成偶数……
两个相邻的数如果都是奇数,那么需要一次操作变成两个偶数,若一奇一偶,则需要两次,所以我们先解决两个奇数的情况,再去考虑两个偶数的情况
对了,一开始要先判一下初始序列的gcd是否大于1。。。
题意:给定两个长度为n的序列A,B,选择一些下标集合T,使2*sigma(A[i]) i∈T >sigma(A) &&2*sigma(B[i]) i∈ T>sigma(B) size_T<=n/2+1;
第一反应……排个序就好了?但是显然不一定最优
那显然取的越多越好,我们就去n/2+1个数字好了
那么怎么分配呢
其实我们可以认为 只要选择的数字和大于未选择的数字和就可以了
所以我们按A排序后,先选择第一个,然后在2、3两个中选择B较大的一个,这样第一个的A一定未大于选择的A,而B较大的一个已经被选,同理,以当前选择的这个数字为“1”,往后推即可
如果是n为偶数……记得把最后一个加上去
当然不加也没关系
E:Mike
and code of a permutation
这题好难啊OTZ
题意我拷别人博客了。。
“
题意:
排列p,编码了一个序列a。对于每个i,找到第一个P
jpj>piPpi
pj>pi并且未被标记的j,标记这个j并a[i]=ja[i]=j。给出a求一个可行的p,保证有解。n≤500000
”
显然可以得到的大小关系在题目中是 p[a[i]]>p[i]
接下来我们考虑间接得到的大小关系:
定义ys[i]表示i这个数字被几号选中,如a[4]=2则ys[2]=4
对于i,如果j∈[1,a[i]-1]且未被选中过,那么p[j]一定大于p[i],否则a[i]=j,即若ys[j]>i,则p[j]>p[i]
这个很显然
根据这两个大小关系我们就可以构建一个有向图,接下来我们只需要一次dfs的拓扑排序就可以了
然后。。数据范围显然不资磁我们n^2去判第二个大小关系
那怎么办。。。
仔细看这个条件……和区间有关。那么线段树套上去啊,就可以做到n*lg级别了
还有,对于-1,我们可以认为是大于之后所有的数,记为n+1
同理,ys初始值为n+1
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define mk make_pair
#define pa pair<int,int>
#define maxn 1000501
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
bool vis[maxn];
int n,ys[maxn],R[maxn*4],L[maxn*4],lson[maxn*4],rson[maxn*4],tim[maxn],T,rt,tot,a[maxn],ans[maxn];
pa ed[maxn*4],tmp;
inline void build(int &x,int l,int r)
{
x=++tot;L[x]=l;R[x]=r;
if(l==r)
{
ed[x]=mk(ys[l],l);
return;
}
int mid=(l+r)>>1;
build(lson[x],l,mid);build(rson[x],mid+1,r);
ed[x]=max(ed[lson[x]],ed[rson[x]]);
}
inline void query(int x,int l,int r)
{
if(l<=L[x]&&R[x]<=r)
{
tmp=max(tmp,ed[x]);
return;
}
if(l<=R[lson[x]]) query(lson[x],l,r);
if(r>=L[rson[x]]) query(rson[x],l,r);
}
inline void del(int x,int to)
{
if(L[x]==R[x])
{
ed[x]=mk(0,1);
return;
}
if(to<=R[lson[x]]) del(lson[x],to);else del(rson[x],to);
ed[x]=max(ed[lson[x]],ed[rson[x]]);
}
inline void dfs(int x)
{
del(1,x);
vis[x]=1;
if(ys[x]!=n+1) if(!vis[ys[x]]) dfs(ys[x]);
if(a[x]>1)
while(1)
{
tmp=mk(0,0);
query(1,1,a[x]-1);
if(tmp.first>x) dfs(tmp.second);else break;
}
tim[++T]=x;
}
int main()
{
scanf("%d",&n);
For(i,1,n) ys[i]=n+1;
For(i,1,n)
{
scanf("%d",&a[i]);
if(a[i]!=-1) ys[a[i]]=i;else a[i]=n+1;
}
build(rt,1,n);
For(i,1,n) if(!vis[i]) dfs(i);
For(i,1,n) ans[tim[i]]=i;
For(i,1,n) printf("%d ",ans[i]);
}
题意就是让你判断一个字符串最多修改一个字符后能不能成为一个回文串。。
所以只要判回文的时候记录一下有多少个不同的位置就行了
B:Mike and strings
不知道可不可以贪心,题意是给你n个字符串,然后你每次操作可以把一个字符串的第一个字符放到最后面,问最少多少次能让所有字符串一样
。。。反正直接枚举一个标准字符串, 然后模拟就行了
C:Mike and gcd problem
这题还是比较有意思的……
题意:给定一个序列A,每次操作可以选出其中两个数字x,y,删除,并且加入x+y,x-y两个数字,问最少多少次操作让序列的gcd>1
很显然的是,两个新加入的数字的gcd若不是1则必然是偶数,所以我们就贪心的认为尽可能把序列中所有的数字变成偶数……
两个相邻的数如果都是奇数,那么需要一次操作变成两个偶数,若一奇一偶,则需要两次,所以我们先解决两个奇数的情况,再去考虑两个偶数的情况
对了,一开始要先判一下初始序列的gcd是否大于1。。。
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <queue> #include <string> #include <map> #include <cstring> #include <ctime> #include <vector> #define inf 1e9 #define ll long long #define For(i,j,k) for(int i=j;i<=k;i++) #define Dow(i,j,k) for(int i=k;i>=j;i--) using namespace std; int t,tmp,tot,n,ans; int a[5000001]; inline int gcd(int x,int y){return y==0?x:gcd(y,x%y);} int main() { scanf("%d",&n); scanf("%d",&a[1]),tmp=a[1]; For(i,2,n) { scanf("%d",&a[i]); if(a[i]&1) tot++;tmp=gcd(a[i],tmp); } if(tmp>1) { puts("YES"); puts("0");return 0; } For(i,1,n) a[i]=a[i]&1; puts("YES"); For(i,2,n) if(a[i]&&a[i-1]) { a[i]=a[i-1]=0; ans++; } For(i,2,n) if(a[i]^a[i-1]) { a[i]=a[i-1]=0; ans+=2; } printf("%d",ans); }D:Mike and distribution
题意:给定两个长度为n的序列A,B,选择一些下标集合T,使2*sigma(A[i]) i∈T >sigma(A) &&2*sigma(B[i]) i∈ T>sigma(B) size_T<=n/2+1;
第一反应……排个序就好了?但是显然不一定最优
那显然取的越多越好,我们就去n/2+1个数字好了
那么怎么分配呢
其实我们可以认为 只要选择的数字和大于未选择的数字和就可以了
所以我们按A排序后,先选择第一个,然后在2、3两个中选择B较大的一个,这样第一个的A一定未大于选择的A,而B较大的一个已经被选,同理,以当前选择的这个数字为“1”,往后推即可
如果是n为偶数……记得把最后一个加上去
当然不加也没关系
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <queue> #include <string> #include <map> #include <cstring> #include <ctime> #include <vector> #define inf 1e9 #define ll long long #define For(i,j,k) for(int i=j;i<=k;i++) #define Dow(i,j,k) for(int i=k;i>=j;i--) using namespace std; int t,tmp,tot,n,ans; struct node { int x,y,num; }a[300001]; int ANS[300001]; inline bool cmp(node x,node y) { return x.x>y.x; } int main() { scanf("%d",&n); For(i,1,n) scanf("%d",&a[i].x),a[i].num=i; For(i,1,n) scanf("%d",&a[i].y); sort(a+1,a+n+1,cmp); ans=n/2+1; printf("%d\n",ans); ANS[++tot]=a[1].num; For(i,1,n/2) { if(i*2+1>n) break; int t1=i*2,t2=i*2+1; if(a[t1].y>a[t2].y) ANS[++tot]=a[t1].num;else ANS[++tot]=a[t2].num; } if(n%2==0) ANS[++tot]=a .num; For(i,1,tot) printf("%d ",ANS[i]); }
E:Mike
and code of a permutation
这题好难啊OTZ
题意我拷别人博客了。。
“
题意:
排列p,编码了一个序列a。对于每个i,找到第一个P
jpj>piPpi
pj>pi并且未被标记的j,标记这个j并a[i]=ja[i]=j。给出a求一个可行的p,保证有解。n≤500000
”
显然可以得到的大小关系在题目中是 p[a[i]]>p[i]
接下来我们考虑间接得到的大小关系:
定义ys[i]表示i这个数字被几号选中,如a[4]=2则ys[2]=4
对于i,如果j∈[1,a[i]-1]且未被选中过,那么p[j]一定大于p[i],否则a[i]=j,即若ys[j]>i,则p[j]>p[i]
这个很显然
根据这两个大小关系我们就可以构建一个有向图,接下来我们只需要一次dfs的拓扑排序就可以了
然后。。数据范围显然不资磁我们n^2去判第二个大小关系
那怎么办。。。
仔细看这个条件……和区间有关。那么线段树套上去啊,就可以做到n*lg级别了
还有,对于-1,我们可以认为是大于之后所有的数,记为n+1
同理,ys初始值为n+1
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define mk make_pair
#define pa pair<int,int>
#define maxn 1000501
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
bool vis[maxn];
int n,ys[maxn],R[maxn*4],L[maxn*4],lson[maxn*4],rson[maxn*4],tim[maxn],T,rt,tot,a[maxn],ans[maxn];
pa ed[maxn*4],tmp;
inline void build(int &x,int l,int r)
{
x=++tot;L[x]=l;R[x]=r;
if(l==r)
{
ed[x]=mk(ys[l],l);
return;
}
int mid=(l+r)>>1;
build(lson[x],l,mid);build(rson[x],mid+1,r);
ed[x]=max(ed[lson[x]],ed[rson[x]]);
}
inline void query(int x,int l,int r)
{
if(l<=L[x]&&R[x]<=r)
{
tmp=max(tmp,ed[x]);
return;
}
if(l<=R[lson[x]]) query(lson[x],l,r);
if(r>=L[rson[x]]) query(rson[x],l,r);
}
inline void del(int x,int to)
{
if(L[x]==R[x])
{
ed[x]=mk(0,1);
return;
}
if(to<=R[lson[x]]) del(lson[x],to);else del(rson[x],to);
ed[x]=max(ed[lson[x]],ed[rson[x]]);
}
inline void dfs(int x)
{
del(1,x);
vis[x]=1;
if(ys[x]!=n+1) if(!vis[ys[x]]) dfs(ys[x]);
if(a[x]>1)
while(1)
{
tmp=mk(0,0);
query(1,1,a[x]-1);
if(tmp.first>x) dfs(tmp.second);else break;
}
tim[++T]=x;
}
int main()
{
scanf("%d",&n);
For(i,1,n) ys[i]=n+1;
For(i,1,n)
{
scanf("%d",&a[i]);
if(a[i]!=-1) ys[a[i]]=i;else a[i]=n+1;
}
build(rt,1,n);
For(i,1,n) if(!vis[i]) dfs(i);
For(i,1,n) ans[tim[i]]=i;
For(i,1,n) printf("%d ",ans[i]);
}
相关文章推荐
- 解题报告:Codeforces Round #193 (Div. 2) C. Students' Revenge 贪心
- Codeforces Round #180 (Div. 2) 解题报告
- Codeforces Beta Round #34 (Div. 2) A题解题报告
- Codeforces Round #380 (Div. 2) 解题报告
- Codeforces Round #306 (Div. 2) D.E. 解题报告
- CF183 div2 解题报告
- Codeforces Round #467 (Div. 2) 解题报告
- Codeforces Round #179 (Div. 2) A题解题报告
- Codeforces Round #188 (Div. 2) A题解题报告
- Codeforces Round #185 (Div. 2) A题解题报告
- Topcoder SRM629 DIV2 解题报告
- 【解题报告】Codeforces Round #378 (Div. 2)
- [Codeforces] Round #249 (Div. 2)解题报告(ABC)
- Codeforces Round #337 (Div. 2) 解题报告
- Codeforces Beta Round #95 (Div. 2) 部分解题报告 (dp,组合数,)
- Codeforces Round #237 (Div. 2)B. Marathon解题报告
- Codeforces Round #238 (Div. 2)前3题解题报告
- Codeforces Round #240 (Div. 2)(前三题解题报告)
- codeforces Round #241(div2) B解题报告
- codeforces Round #241(div2) D解题报告