A.The Rank
手速题,给你一堆人的成绩,问你其中第一个人的总分排第几(总分相同按出现顺序排)。
那保存第一个人的成绩,先放在第一名,然后后面每有一个成绩比他高的,排名就加一。最后复杂度是O(n)。
我手贱,打了个结构体,大家就当没看见。
struct stu
{
int id,a,b,c,d;
} s[1005];
bool operator > (stu x,stu y)
{
if(x.a+x.b+x.c+x.d>y.a+y.b+y.c+y.d)return 1;
return 0;
}
int main()
{
int n,ans;
cin>>n;
ans=1;
stu smith;
cin>>smith.a>>smith.b>>smith.c>>smith.d;
for(int i=1;i<n;i++)
{
stu tmp;
cin>>tmp.a>>tmp.b>>tmp.c>>tmp.d;
if(tmp>smith)ans++;
}
cout<<ans;
return 0;
}
B.The Bits
给你一个长度为n的01串a,再给你一个等长的01串b。然后我们有一个c=a&b。现在我们可以把a中任意两个字符交换位置,得到a’,有c’=a’&b。问有多少种换法,使得c’!=c。
因为数据范围是1e5,如果穷举的话,也就1e10,还是有几率可以过的嘛。但是我们很快发现这道题有很强的相似性,对于a,b在同一个位置上的数,总共只有四种状态,即:
○ A B
① 0 0
② 0 1
③ 1 0
④ 1 1
因为我们只能互换a中的数字,那么总共有C(4,2)种可能的换法。穷举之后发现①③,①④,②③中的A交换以后会改变,而其他换法不会改变。所以我们只要统计四种状态分别的个数,最后结果就是① * ③ + ① * ④ + ② * ③。
int main()
{
int n;
string a,b;
long long cnt1=0,cnt2=0,cnt3=0,cnt4=0;
cin>>n>>a>>b;
for(int i=0;i<n;i++)
{
if(a[i]=='0'&&b[i]=='0')cnt1++;
if(a[i]=='0'&&b[i]=='1')cnt2++;
if(a[i]=='1'&&b[i]=='0')cnt3++;
if(a[i]=='1'&&b[i]=='1')cnt4++;
}
cout<<(cnt1*cnt3+cnt1*cnt4+cnt2*cnt3)<<endl;
return 0;
}
C.The Phone number
让你求一个N的全排列,使它的最长上升子序列的长度与最长下降子序列的长度之和最小。
我的直觉告诉我,分块。。。
(其实我一开始是中间切开做的,后来被大佬提醒才对了,太真实了)
那反正就是取q=sqrt(n),把n切成尽量等长的q个小段,然后。。比较难解释,举个例子,比如n=13,那么q=3。我们把它切成长度为4,4,5的三段,然后:
4 3 2 1 / 8 7 6 5 /13 12 11 10 9
这样上升子序列的长度是3(大段个数),下降子序列长度是5(小段长度的最大值),结果就是8。证明的话,我没想到特别严谨的证明,就希望有大佬提供思路。本蒻简陋证明如下:
首先,根据上面的构造法,我们得到的答案大小为q+(n+q-1)/q,记为M,我们假设存在一个比它更小的答案m。
我们考虑一个长度为n-1的以及排好的全排列,然后向里面插入一个n。可以证明,如果放在第一个,那么所有原来的下降序列长度+1;如果在最后一个,那么所有原来的上升序列长度+1;如果再中间,那么就使左边的上升序列长度+1,右边的下降序列长度+1。
n==1时,答案为2(1+1)。
对于每一次操作,若放在最左或最右,必定使答案+1。那么最终答案是n+1。
而若是放在中间,我们把两边的撇开,里面是一个类似的问题。然后通过某种玄学的方法,我们可以认为最终结果应该是和sqrt(n)有关的一个数,也就是分块的结果。
int main()
{
int n;
cin>>n;
int p=sqrt(n),q=n/p;
int cnt=q;
for(int i=0;i<p;i++)
{
for(int j=0;j<q;j++)
{
cout<<cnt<<" ";
cnt--;
}
cnt+=2*q;
}
if(p*q<n)for(int i=n;i>p*q;i--)cout<<i<<" ";
return 0;
}
D.The Wu
这是一道比较复杂的模拟题,难度不大,关键在于位运算和预处理。
http://codeforces.com/contest/1017/problem/D
void read(int &x)
{
x=0;char ch=getchar();
while(ch<'0'||ch>'9'){ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return;
}
int bitread()
{
int base=1;
int x=0;char ch=getchar();
while(ch<'0'||ch>'9'){ch=getchar();}
while(ch>='0'&&ch<='9')
{
if(ch=='1')x+=base;
ch=getchar();
base=base*2;
}
return x;
}
int lowbit(int x)
{
return x&-x;
}
int w[4100];
int cnt[4100];
int ans[4100][105];
int n,m,q;
int N;
int lazy_tag[105];
int main()
{
memset(cnt,0,sizeof(cnt));
memset(ans,0,sizeof(ans));
read(n);read(m);read(q);
N=1<<n;
for(int i=0;i<n;i++)read(w[1<<i]);
for(int i=0;i<((N));i++)
{
int sum=0;
int t=i;
while(t)
{
int lb=lowbit(t);
sum+=w[lb];
t-=lb;
}
w[i]=sum;
}
for(int i=0;i<m;i++)cnt[bitread()]++;
for(int i=0;i<((N));i++)
{
memset(lazy_tag,0,sizeof(lazy_tag));
for(int j=0;j<((N));j++)
{
int b=i^j^((N)-1);
if(w[b]>100)continue;
lazy_tag[w[b]]+=cnt[j];
// for(int k=w[b];k<=100;k++)ans[i][k]+=cnt[j];
}
int summ=0;
for(int hh=0;hh<=100;hh++)
{
summ+=lazy_tag[hh];
ans[i][hh]+=summ;
}
}
while(q--)
{
int aa,bb;
aa=bitread();
read(bb);
cout<<ans[aa][bb]<<endl;
}
}