t1
在桌面上放着n张纸牌,每张纸牌有两面,每面都写着一个非负整数。你的邪王真眼可以看到所有牌朝上的一面和朝下的一面写的数字。现在你需要将一些牌翻过来,使得所有牌朝上的一面中,至少有一半(≥n/2)的数字是一样的。请你求出最少需要翻几张牌,或者判断无解。
注意:在翻牌的时候,你不能把牌扔掉,不能偷偷把别的牌放进来,也不能用笔涂改牌上面的数字。
离散化,在贪心,找最多的向上的,个数大于n/2的
#include<cstdio>
#include<algorithm>
using namespace std;
int n,b[110000],a[110000],tmp[119999],tot,cnt[110000],cnt2[110000],maxn;
int main(){
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]),tmp[++tot]=a[i];
scanf("%d",&b[i]),tmp[++tot]=b[i];
}
sort(tmp+1,tmp+tot+1);
int t1=unique(tmp+1,tmp+tot+1)-tmp-1;
//for(int i=1;i<=t1;i++) printf("%d ",tmp[i]);
for(int i=1;i<=n;i++)
a[i]=lower_bound(tmp,tmp+t1+1,a[i])-tmp-1,b[i]=lower_bound(tmp+1,tmp+t1+1,b[i])-tmp-1;
for(int i=1;i<=n;i++){
//printf("%d ",a[i]);
cnt[a[i]]++;cnt2[a[i]]++;
cnt[b[i]]+=(a[i]==b[i])?0:1;
}
sort(a+1,a+n+1);
t1=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=t1;i++)
if(cnt[a[i]]>n/2&&cnt2[a[i]]>maxn) maxn=cnt2[a[i]];
//printf("%d ",maxn);
if(maxn<(n+1)/2&&maxn)
printf("%d",(n+1)/2-maxn);
else if(maxn>(n+1)/2) printf("0");
else printf("Impossible");
}
t2
给定一个字符串S,它的长为n,后缀数组的功能是,将其所有后缀按字典序从小到大排好序。我们对其做一点小小的改动:再给定一个数字m,记ssi表示从S的第i位开始、长度最多为m的子串,我们希望将这些字符串{ssi}按字典序从小到大排序。举个栗子,当S=”abcab”,m=2时,ssi的值分别为:
ss1=”ab”
ss2=”bc”
ss3=”ca”
ss4=”ab”
ss5=”b”
但是,只是把{ssi}全部排好序还是太简单了。初始状态下,ss1~ssn按顺序排成一行,我们只能通过不断交换某两个相邻字符串的位置来做排序。再举个栗子,把上面提到的ss1~ss5排好序的一种方案是:
(0)原序列:”ab”, “bc”, “ca”, “ab”, “b”
(1)交换第3和第4个串:”ab”, “bc”, “ab”, ca”, “b”
(2)交换第2和第3个串:”ab”, “ab”, “bc”, ca”, “b”
(3)交换第4和第5个串:”ab”, “ab”, “bc”, b”, “ca”
(4)交换第3和第4个串:”ab”, “ab”, “b”, bc”, “ca”
现在,你需要求出,最少通过多少次相邻字符串交换,才能把所有子串{ssi}排成字典序从小到大的形式。
归并排序,把比数字大小改成比字典序,用哈希维护,二分第一个不行的
#include <cstdio>
#include<iostream>
#define p 1000000007
#define N 50055
long long n,m,hash[1100000],pow[1100000],a[1100000],f[1100000],tmp[1100000],ans;
bool comp(int l,int r){
if(l==r) return 1;
int L=0,R=m;
if (n-r+2<R) R=n-r+2;
if (n-l+2<R) R=n-l+2;
while(L<=R)
{
int mid=(L+R)>>1;
long long has=(hash[l+mid-1]-1ll*hash[l-1]*pow[mid]%p+p)%p;
long long has2=(hash[r+mid-1]-1ll*hash[r-1]*pow[mid]%p+p)%p;
if(has==has2) L=mid+1;
else R=mid-1;
}
if(L==m) return 1;
return a[l+L-1]<=a[r+L-1];
}
void sort(int l,int r){
if(l==r) return ;
int mid=(l+r)>>1;
sort(l,mid);
sort(mid+1,r);
int t1=l,t2=mid+1,flag;
for(int i=l;i<=r;i++){
if(t1>mid) flag=0;
else if(t2>r) flag=1;
else flag=comp(f[t1],f[t2]);
if(flag)
tmp[i]=f[t1++];
else tmp[i]=f[t2++],ans+=mid-t1+1;
}
for(int i=l;i<=r;i++)
f[i]=tmp[i];
return ;
}
int main(){
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
scanf("%d%d",&n,&m);
pow[0]=1;
for(int i=1;i<=n;i++){
char x;
std::cin>>x;
a[i]=x-96;
hash[i]=(1ll*hash[i-1]*29+a[i])%p;
pow[i]=pow[i-1]*29ll%p;
f[i]=i;
}
a[n+1]=0;
sort(1,n);
printf("%lld",ans);
}