B. XK Segments
题意
给n,x,k,再n个数, 找出有多少对 (i,j)并且a[i] <= a[j],使得在 a[i] <= y <= a[j] 中有k个数可以整除x
n, x, k (1 ≤ n ≤ 105, 1 ≤ x ≤ 109, 0 ≤ k ≤ 109),ai (1 ≤ ai ≤ 109)
分析
直接unordered_map存[1,a[i] ]中有多少个能整除k
k!=0的情况很显然,直接以当前数为左端点,找右端点的个数即可
k==0时,加上和一样的数,不一样但整除数一样的求和/2即可
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1e5 + 10; const ll mod = 1e9 + 7; ll n,x,k; ll a[maxn]; unordered_map<ll,ll>mp; unordered_map<ll,ll>vis; int main() { scanf("%I64d%I64d%I64d ", &n, &x, &k); for(int i = 1;i <= n; i++) { scanf("%I64d", &a[i]); mp[a[i]/x]++; vis[a[i]]++; } ll sum = 0; ll ans=0, num=0; for(int i = 1; i <= n;i++) { if((a[i]%x)==0) { if(k!=0) sum += mp[k+a[i]/x-1]; } else { sum += mp[k+a[i]/x]; if(k==0) { ans+=vis[a[i]]; // mp[k+a[i]/x]-=vis[a[i]]; num+=mp[a[i]/x]-vis[a[i]]; } } } if(k!=0) printf("%I64d ", sum); else printf("%I64d ", ans+num/2); return 0; }
C.Square Subsets
题意
给n个数,问有多少选出任意个数相乘是平方数,答案对1e9+7取模
(1 ≤ n ≤ 105) ,ai (1 ≤ ai ≤ 70)
分析
状压mask dp
首先一个数是平方数,肯定是若干个素数,并且每个质数是偶数个,所以不难想到,如果将70以内的素数(19个),看成19个二进制位,分别化为s[i],表示每一个数二进制位的情况,如果每一位都是0的话,这个数则为平方数。
定义:dp[i][j]表示前1~i个数,mask位 j 的方案数,则dp[70][0]则为答案
转移:考虑当前数i,如果能转移到j,则dp[i][j]=(((dp[i-1][j]+dp[i-1][s[i]^j])%mod)*(fac[cnt[i]-1]))%mod;
组合数C(n,m)从n和数选择m个数,选择奇数个和偶数个的总方案数都为2^(n-1),总的为2^n,因为每一个数都有两种状态0/1
trick:注意将dp[0][0]设为1,并答案减去1,因为只有所有的数都选0个才不符合情况,显然这种情况这有一种
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 524300 ; const int maxm = 1e5 + 3; const ll mod = 1e9+7; int dp[71][maxn]; int fac[maxm]; int cnt[71]; int prime[21]={2 ,3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67}; int n; int s[71]; int main() { for(int i = 1; i <= 70; i++) { int ii=i; for(int j = 0; j < 19; j++) { while(ii%prime[j] == 0) { ii/=prime[j]; s[i]^=(1<<j); } } } fac[0]=1; fac[1]=2; for(int i = 2; i <= 100000; i++) { fac[i]=(2*fac[i-1])%mod; } scanf("%d", &n); int x; for(int i = 1; i <= n; i++) { scanf("%d", &x); cnt[x]++; } dp[0][0]=1; for(int i = 1; i <= 70; i++) { if(!cnt[i]) { for(int j = 0; j < (1<<19); j++) { dp[i][j]=dp[i-1][j]; } } else { for(int j = 0; j < (1<<19); j++) { dp[i][j]=(((dp[i-1][j]+dp[i-1][s[i]^j])%mod)*(fac[cnt[i]-1]))%mod; } } } printf("%d ", dp[70][0]-1); return 0; }
D. String Mark
题意
分析
E. Eyes Closed
题意
分析