Codeforces Round #1323
A Even Subset Sum Problem
传送门:A
Description
给定数组 \(a\),求出它一个和为偶数的的非空子集,输出其元素编号,无解输出 \(-1\)。多组数据。
Solution
没有偶数且奇数个数必定无解。如果存在偶数,那么输出这个偶数就可以了。否则如果奇数个数超过 \(2\),输出两个奇数即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 100 + 10;
int T;
int n,cnt,jsq;
int vis[N],a[N];
signed main()
{
scanf("%d",&T);
//T++;
while(T--)
{
//cout << T << endl;
cnt = jsq = 0;
scanf("%d",&n);
//cout << n << endl;
for(int i = 1;i <= n;i++) vis[i] = 0;
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
for(int i = 1;i <= n;i++)
if(a[i] & 1) cnt++;
else jsq++,vis[i] = 1;
if(jsq == 0 and cnt < 2)
{
printf("-1\n");
continue;
}
if(jsq)
{
printf("1\n");
for(int i = 1;i <= n;i++)
if(vis[i]){ printf("%d\n",i); break; }
}
else
{
int num = 0;
printf("2\n");
for(int i = 1;i <= n;i++)
{
if(vis[i]) continue;
if(num)
{
printf("%d\n",i);
break;
}
printf("%d ",i);
num++;
}
}
}
return 0;
}
B Count Subrectangles
传送门:B
Description
给定长为 \(n\) 的数组 \(a\) 和长为 \(m\) 的数组 \(b\),数组中的元素均是 \(0\) 或 \(1\)。有 \(n\times m\) 的矩阵 \(c\),\(c_{i,j}=a_i \cdot b_j\)。请求出矩阵 \(c\) 面积为 \(k\) 的全 \(1\) 子矩阵数量。样例及解释见题面。
Solution
维护一下横纵分别对于连续的长度为 \(x\) 的 \(1\) 有多少个。然后对于 \(k\) 做质因数分解,用横纵的方案数做乘法原理即可。(注:代码中的二分是不必要的)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 40000 + 10;
struct node
{
int val,num;
}jk[2*N];
int n,m,k,cnt = 1,jsq,ans;
int a[N],b[N];
int fac[2*N];
int f[2*N],g[2*N];
bool cmp(node aa,node bb)
{
return aa.val < bb.val;
}
signed main()
{
memset(fac,0x3f,sizeof(fac));
scanf("%lld%lld%lld",&n,&m,&k);
for(int i = 1;i <= n;i++)
scanf("%lld",&a[i]);
a[n+1] = 0;
for(int i = 1;i <= m;i++)
scanf("%lld",&b[i]);
b[m+1] = 0;
for(int i = 1;i * i <= k;i++)
{
if(i * i == k) fac[++cnt] = i;
else if(k % i == 0)
{
fac[++cnt] = i;
fac[++cnt] = k / i;
}
}
for(int i = 2;i <= cnt;i++) jk[i].val = fac[i],jk[i].num = i;
sort(jk + 2,jk + cnt + 1,cmp);
for(int i = 1;i <= n + 1;i++)
{
if(a[i] == 0)
{
if(not jsq) continue;
//flag1++;
int l = 2,r = cnt + 1;
while(r - l > 1)
{
int mid = (l + r) >> 1;
if(jk[mid].val <= jsq) l = mid;
else r = mid;
}
for(int j = 2;j <= l;j++)
f[jk[j].num] += jsq - jk[j].val + 1;
jsq = 0;
}
else jsq++;
}
jsq = 0;
for(int i = 1;i <= m + 1;i++)
{
if(b[i] == 0)
{
if(not jsq) continue;
//flag2++;
int l = 2,r = cnt + 1;
while(r - l > 1)
{
int mid = (l + r) >> 1;
if(jk[mid].val <= jsq) l = mid;
else r = mid;
}
for(int j = 2;j <= l;j++)
g[jk[j].num] += jsq - jk[j].val + 1;
//cout << jsq << endl;
jsq = 0;
}
else jsq++;
}
int ox = sqrt(k);
if(ox * ox == k) g[cnt+1] = g[cnt];
for(int i = 2;i <= cnt;i++)
ans += f[i] * g[i ^ 1];
/*for(int i = 2;i <= cnt;i++) cout << f[i] << " ";
cout << endl;
for(int j = 2;j <= cnt;j++) cout << g[j] << " ";
cout << endl;
/*for(int i = 1;i <= cnt;i++) cout << fac[i] << " ";
cout << endl;*/
/*for(int i = 1;i <= n + 1;i++) cout << a[i] << " ";
cout << endl;*/
printf("%lld\n",ans);
return 0;
}
C Unusual Competitions
传送门:C
Description
- 有一个长度为 \(n\) 的括号序列。
- 你可以进行若干次操作:花费 \(m\) 的代价,将一个长度为 \(m\) 的括号子串任意排列。
- 若能将括号序列排成合法的括号序,请求出最小花费的代价和。否则请输出 -1。
- \(1\leq n\leq 10^6\)。
Solution
如果左括号数不等于右括号,则必然无解。从前向后扫,维护 \(sum_i\) 表示前 \(i\) 位左括号数与右括号数的差值。如果当前 \(sum_i < 0\),则当前出现了逆序,需要使用一次重排,我们打一个标记。当再次出现 \(sum_i = 0\) 时,我们统计它到上一次个数相同的位置的长度,累加进答案。顺序扫一遍即可。时间复杂度 \(O(n)\)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1000000 + 10;
int n,cnt,jsq,flag,pos,ans;
int sum[N];
char s[N];
signed main()
{
scanf("%d",&n);
scanf("%s",s + 1);
for(int i = 1;i <= n;i++)
s[i] == '(' ? cnt++ : jsq++;
if(cnt != jsq)
{
printf("-1\n");
return 0;
}
for(int i = 1;i <= n;i++)
{
sum[i] = s[i] == '(' ? sum[i-1] + 1 : sum[i-1] - 1;
if(sum[i] < 0) flag = 1;
if(sum[i] == 0)
{
if(flag == 1)
ans += i - pos;
pos = i,flag = 0;
}
}
printf("%d\n",ans);
return 0;
}
D Present
传送门:D
Description
- 给出一个长度为 \(n\) 的数列 \(a\)。其中第 \(i\) 项为 \(a_i\)。
- 请你求出 \(\bigoplus_{i=1}^{n}\bigoplus_{j=i+1}^{n}(a_i+a_j)\)。其中 \(\oplus\) 表示按位异或操作。
- \(2\leq n\leq 4\times 10^5\),\(1\leq a_i \leq 10^7\)。
Solution
求异或的话一般按位考虑。
对于第 \(k\) 位,考虑只有后面 \(k\) 位会对该答案产生影响,所以对 \(2^{k+1}-1\) 取模。
对于取完模的两个数为了使第 k 位为 \(1\),则和必在 \([2^k,2^{k+1}-1]\) 或 \([2^k+2^{k+1},2^{k+2}-1]\) 之内。
排序后双指针维护满足的答案对数,判断奇偶即可维护出第 \(k\) 位。(注意位运算的优先辑,打括号)
#include<bits/stdc++.h>
using namespace std;
const int N = 400000 + 10;
int n,ans;
int a[N],t[N];
int cal(int ls,int rs)
{
if(rs < ls) return 0;
int l = 1,r = 1,res = 0;
for(int i = n;i >= 1;i--)
{
while(l <= n and t[i] + t[l] < ls) l++;
while(r <= n and t[i] + t[r] <= rs) r++;
if(i >= l and i < r) res += r - l - 1;
else res += r - l;
}
return res >> 1 & 1;// 判断奇偶
}
int sol(int k)
{
for(int i = 1;i <= n;i++)
t[i] = a[i] & ((1 << (k + 1)) - 1);
sort(t + 1,t + n + 1);
return (cal(1 << k,(1 << (k + 1)) - 1) + cal(3 << k,(1 << (k + 2)) - 1)) & 1;
}
signed main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
for(int i = 0;i <= 25;i++) ans |= sol(i) << i;
printf("%d\n",ans);
return 0;
}
E Instant Noodles
传送门:E
F Reality Show
传送门:F

浙公网安备 33010602011771号