A. Even Subset Sum Problem
题意:给出一组数,求其一个和为偶数的子集。
解:略
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <algorithm> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n; int a[maxx]; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); if(n==1&&a[1]%2==1) printf("-1\n"); else { for(int i=1;i<=n;i++){ if(a[i]%2==0){ printf("1\n"); printf("%d\n",i); goto nxt; } } printf("2\n"); int cnt=0; for(int i=1;i<=n;i++){ if(a[i]%2){ printf("%d ",i); cnt++; if(cnt==2){ printf("\n"); goto nxt; } } } } nxt:; } return 0; }
B. Count Subrectangles
题意:给出两个长度为n的01序列,按矩阵相乘得出一个n*n的矩阵,求矩阵中大小为k的由1组成的长方形有多少。
解:显然只有行和列都为1时对应格为1,也就是说,设a*b=k,则两个数组中须有连续长为a的1和连续长为b的1,将连续段相乘即为答案。(一开始先处理出每个数组各有多少个连续的1,结果一直RE,后面换成要用的时候再找就不RE了,或许还快一点,毕竟k的因子也没几个。。。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 1000005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,m,k; char a[maxx]; int b[maxx]={0}; signed main() { scanf("%d",&n); scanf("%s",a+1); int l=0,r=0; for(int i=1;i<=n;i++){ if(a[i]=='(') l++; else r++; b[i]=l-r; } if(l!=r){ printf("-1\n"); return 0; } int pos=0,ans=0; for(int i=1;i<=n;i++){ if(b[i]==0){ if(b[i-1]==1) { pos=i; continue; } ans+=i-pos; pos=i; } } printf("%d\n",ans); return 0; }
C. Unusual Competitions
题意:给定一个括号序列,每次可选一个子区间随意排列,问至少重排多长的序列后可以使整串括号合法。
解:既然不是问次数,而是问总长度,那看到不合法的序列,找到能让它合法的位置,就重排。合法的位置很好找,当区间内左右括号数量相等时即可。考虑判断原来就合法的序列有什么特点,当然可以用栈,但其实观察左右括号个数,如果截止到前一个括号,左比右多一个,那一定合法。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 1000005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,m,k; char a[maxx]; int b[maxx]={0}; signed main() { scanf("%d",&n); scanf("%s",a+1); int l=0,r=0; for(int i=1;i<=n;i++){ if(a[i]=='(') l++; else r++; b[i]=l-r; } if(l!=r){ printf("-1\n"); return 0; } int pos=0,ans=0; for(int i=1;i<=n;i++){ if(b[i]==0){ if(b[i-1]==1) { pos=i; continue; } ans+=i-pos; pos=i; } } printf("%d\n",ans); return 0; }
D. Present
题意:很粗暴的题意,计算:
,0<=n<=4e5
解:昨天做的时候一直试图给它们配对,看看有什么能抵消的。。。以后看见异或还是按位拆吧。
这串东西的意思是每两个数都结合一遍。也就是说把它们排成一列,每两个都能拎出来加一加。考虑第k位是不是1。枚举每个数,看有多少数和其相加后第k位为1。第k位为1,第k+1位,k+2位也有可能为1,也就是两者和有两种可能,[2k,2k+1-1]和[2k+2k+1,2k+2-2]。现在要算这两个区间内有多少数,应当用二分查找。二分查找要排序,由于现在只看末k+1位,还要先模一下。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 400005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n; int a[maxx]={0}; int b[maxx]; int p[30]; int cal(int k){ for(int i=1;i<=n;i++) b[i]=a[i]%(1<<(k+1)); sort(b+1,b+n+1); int res=0; for(int i=1;i<=n;i++){ res+=upper_bound(b+i+1,b+n+1,p[k+1]-1-b[i])- lower_bound(b+i+1,b+n+1,p[k]-b[i]); res+=upper_bound(b+i+1,b+n+1,p[k+2]-2-b[i])- lower_bound(b+i+1,b+n+1,p[k]+p[k+1]-b[i]); } return res%2; } // k k+1 k+2 // [2^k,2^(k+1)-1] // [2^k+2^(k+1),2^(k+2)-2] signed main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=0;i<=26;i++) p[i]=1<<i; int ans=0; for(int i=0;i<=24;i++){ if(cal(i)) ans+=1<<i; } printf("%d\n",ans); return 0; }
E. Instant Noodles
建议改名随意起名谜语人场(
题意:有一个二分图,左边n个结点,右边n个结点。右边每个结点都有一个权值。取左边结点的一个子集,令N(S)为所有与子集中点相连的右部结点,f(S)为N(S)的权值和。求所有f(S)的gcd。
解:看起来有很多子集,很麻烦,好在求的是gcd。已知gcd(a,b)=gcd(a+b,b)=gcd(a+b,a)。也就是说,有了a和b,就不用求a+b了,只要找出能合并出全集的几个集合就可以了。有一个朴素的想法,将每一个左部顶点对应的右部顶点之和求出来,一起gcd。但是有一个问题,当两个结点共用一个右部结点时它们的和就不是a+b了,所以不行。详见样例2。因此考虑合并右部结点。条件挺苛刻的,两个右部结点,如果对应左部结点完全相同才能合并,这样一来就没有会被共用的点了,可以直接求gcd。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 500005 #define maxn 1005 #define maxm 200005 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,m; ll a[maxx]; ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); int x,y; map<int,set<int> > m1; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); m1[y].insert(x); } map<set<int>,ll> m2; for(auto [x,s]:m1) m2[s]+=a[x]; ll ans=0; for(auto [s,x]:m2) ans=gcd(ans,x); printf("%lld\n",ans); } return 0; }
(用vector没过,用set过了,怪耶