Codeforces Round #410 (Div. 2) 解題報告

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。。。

#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[n].num;
	For(i,1,tot)	printf("%d ",ANS[i]);
}

E:Mike and code of a permutation

這題好難啊OTZ

題意我拷別人博客了。。

題意:

排列p,編碼了一個序列a。對於每個i,找到第一個P

j
pj>piPpi
     pj>pi
並且未被標記的j,標記這個j並a[i]=ja[i]=j。給出a求一個可行的p,保證有解。n500000


顯然可以得到的大小關係在題目中是 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]);
}	


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章