比赛链接:Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)
A. Even Subset Sum Problem
题意:找一个子集sum为偶数;
分析:xjb写
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const int mod=1e9+7;
const ll INF=1e18;
int a[maxn];
void rua()
{
int n,num=-1;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
if(a[i]%2==0)
{
printf("1\n%d\n",i);
return;
}
else
{
if(num!=-1)
{
printf("2\n%d %d\n",num,i);
return;
}
else num=i;
}
}
printf("-1\n");
}
int main()
{
int t;scanf("%d",&t);
while(t--) rua();
return 0;
}
B. Count Subrectangles
题意:矩阵cij=ai*bj,求有多少个面积为k的全1子矩阵;
分析:通过前缀和分别对abO(n)处理出连续为1的不同长度的个数,答案就是k的所有因子对对应个数的乘积;
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const int mod=1e9+7;
const ll INF=1e18;
int a[maxn],b[maxn],sa[maxn],sb[maxn];
void rua()
{
int n,m,k;scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
for(int i=0;i<m;i++) scanf("%d",&b[i]);
int num=0;a[n]=b[m]=0;
for(int i=0;i<=n;i++)
{
if(a[i]==0) num=0;
else num++,sa[1]++,sa[num+1]--;
}
for(int i=0;i<=m;i++)
{
if(b[i]==0) num=0;
else num++,sb[1]++,sb[num+1]--;
}
for(int i=1;i<=n;i++) sa[i]+=sa[i-1];
for(int i=1;i<=m;i++) sb[i]+=sb[i-1];
ll ans=0;
for(int i=1;i<=n;i++)
{
if(k%i!=0) continue;
int j=k/i;
if(j>m) continue;
ans+=1ll*sa[i]*sb[j];
}
printf("%lld\n",ans);
}
int main()
{
rua();
return 0;
}
C. Unusual Competitions
题意:给一段左右括号的字符串,任意长度子区间可以任意排序,代价为区间长度,求使得括号正确匹配的最小代价;
分析:贪心选择尽可能短的区间处理;s1 s2 分别记下未正确匹配的个数,s1==s2且不为0时,这一段就可以处理;
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
const int mod=1e9+7;
const ll INF=1e18;
char s[maxn];
void rua()
{
int n;scanf("%d",&n);
scanf("%s",s+1);
int s1=0,s2=0,ans=0,l;
for(int i=1;i<=n;i++)
{
if(s[i]=='(') s1++;
else s2++;
}
if(s1!=s2) {printf("-1\n");return;}
s1=s2=0;l=1;
if(s[1]=='(') s1++;
else s2++;
for(int r=2;r<=n;r++)
{
if(s[r]=='(') s1++;
else
{
if(s1) s1--;
else s2++;
}
if(s1==s2)
{
if(s1!=0) ans+=(r-l+1);
l=r+1;
s1=s2=0;
}
}
printf("%d\n",ans);
}
int main()
{
rua();
return 0;
}
D.Present
题意:给你n个数,求任意两个数和的异或值;
分析:显然能想到二进制运算,由于加法存在进位,所以低位对高位会产生影响,高位对低位则不会,因此考虑从低位向高位处理;每个数都对(1<<(i+1))取模,那么所有数的范围都在[0,1<<(i+1)-1],不考虑比i高的位置;那么最终答案二进制下第i位是否为1就取决于是否有奇数对和在这个位置为1,两两求和可以枚举其中一个,二分找到对第i位产生影响的数的个数;
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn=4e5+7;
const int mod=1e9+7;
const ll INF=1e18;
int a[maxn],b[maxn];
void rua()
{
int n,ans=0;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<28;i++)
{
for(int j=1;j<=n;j++) b[j]=a[j]%(1<<(1+i));
sort(b+1,b+1+n);
ll num=0;
for(int j=1;j<=n;j++)
{
//b[j]+b[k]>=(1<<(i+1))+(1<<i) 11xxxx此时都满足
ll res=lower_bound(b+1,b+1+n,(1<<(i+1))+(1<<i)-b[j])-b-1;
num+=n-res;
if(2*b[j]>=(1<<(i+1))+(1<<i)) num--;//排除自己加自己
//b[j]+b[k]>=(1<<i) 01xxxx/10xxxx/11xxxx 此时只要01xxxx 因为11xxxx已经算过了
ll s1=lower_bound(b+1,b+1+n,(1<<i)-b[j])-b-1;
//b[j]+b[k]>=(1<<(i+1)) 10xxxx/11xxxx 这些都不要
ll s2=lower_bound(b+1,b+1+n,(1<<(i+1))-b[j])-b-1;
num+=(s2-s1);
if(2*b[j]>=(1<<i) && 2*b[j]<(1<<(i+1))) num--;//排除自己加自己
}
num>>=1;//每一对都算了两遍
if(num&1) ans+=(1<<i);
}
printf("%d\n",ans);
}
int main()
{
rua();
return 0;
}