D
数组长度为2*1e5 ,我们知道如果超过30个非(-1,1)的数字相乘一定是大于查询的值域的
所以如果超过60(30*2)个数字,那么一定不能构成查询的数,而如果小于60个则可以暴力预处理一下,求出并记录,每个值变化时数组的乘积,在查询中直接查询
需要注意的是0是一定可以达到的,只需把一个数变成0,那么数组的乘积都是0
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N];int n,q;
map<int,int>mp;void solve(){cin>>n>>q;set<int>s;for(int i=1;i<=n;i++){cin>>a[i];s.insert(a[i]);} int t=sqrt(1e9)+1;if(s.size()<=60){for(auto c:s){for(int j=c-t;j<=c+t;j++){int res=1;for(int i=1;i<=n;i++){res=res*(a[i]-j);if(abs(res)>1e9) break;}if(abs(res)<=1e9)mp[res]=1;}}}mp[0]=1;int m;while(q--){cin>>m;if(mp.count(m)) cout<<"Yes\n";else cout<<"No\n";}
}
signed main(){int t=1;//cin>>t;while(t--){solve();}
}
F
第二类斯特林数模板
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7;
int a[N],v[N],w[N],ans[N];
int in[N],inv[N];
int n,m;
int qmi(int a,int b){int res=1;while(b){if(b&1) res=(res*a)%mod;a=(a*a)%mod;b>>=1;}return res;
}
void inti(){int res=1;in[0]=1;for(int i=1;i<=N;i++){in[i]=(in[i-1]*i)%mod;}
}
void solve(){cin>>n>>m;inti();int ans=0;for(int i=0;i<=m;i++){ans=(ans+(qmi(-1,m-i)*qmi(i,n))%mod*qmi(in[i]*in[m-i]%mod,mod-2))%mod;}cout<<ans<<endl;
}
signed main(){int t=1;while(t--){solve();}
}
H
让我们看这样一个二进制数
我们可以O(n)求出它对应的数组的和
如何考虑更优解
我们注意到如果把最高位的1改成0,我们就可以把更低的位全部变成1
这么做的贡献为所有
减去所有\sum a[i] &10000000=10000000
这样我们可以尝试去掉每一位1,然后O(n)求一下和,取最大值即是答案
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N],v[N],w[N],ans[N];int n,m;
int get(int x){int res=0;for(int i=1;i<=n;i++){if((w[i]&x)==w[i]) res+=v[i];}return res;
}
void solve(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>v[i]>>w[i];} int ans=get(m);for(int i=m;i;i-=(i&(-i))){ans=max(ans,get(i-1));}cout<<ans<<endl;
}
signed main(){int t=1;cin>>t;while(t--){solve();}
}
J
奇妙的二分
枚举最大距离
二分的过程中尝试
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N];void solve(){int x,y,w;int n;cin>>n>>x>>y;for(int i=1;i<=n;i++){cin>>a[i];}auto check=[&](int d){int last=y;set<int>s;if(abs(x-y)<=d) s.insert(x);for(int i=1;i<=n;i++){if(s.size() && abs(a[i]-last)<=d) s.insert(last); while(s.size() && *s.begin()<a[i]-d) s.erase(s.begin());while(s.size() && *s.rbegin()>a[i]+d) s.erase(*s.rbegin());last=a[i];}return s.size();};int l=0,r=1e9+1;while(l<r){int mid=l+r>>1;if(!check(mid)){l=mid+1;}else{r=mid;}}cout<<l<<endl;
}
signed main(){int t=1;while(t--){solve();}
}
K
模拟一下可知
部分题目连接在一起可以形成一个环(加上其他连向环的边形成基环树,这里如果环内确定下来,那么环外的选择就已经确定了,可以反推,所有只需要考虑环内的数量即可),如果环头和环尾不一致则不成一个方案。
我们直接从环上的点开始模拟,依次求出每个选择是否可行(根据上文的方法)
求出所有环的方案数相乘即是答案
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010,mod=998244353;
int a[N],d[N];
bool st[N];
string str[N];
void solve(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i]>>str[i];d[a[i]]++;}queue<int>q;for(int i=1;i<=n;i++){if(!d[i]) q.push(i);}while(q.size()){int t=q.front();q.pop();st[t]=1;if(--d[a[t]]==0){q.push(a[t]);}}int ans=1;for(int i=1;i<=n;i++){if(st[i]) continue;//cout<<i<<endl;int res=0;for(int j=0;j<5;j++){int now=i;st[now]=1;int nowop=j;while(1){nowop=str[now][nowop]-'A';now=a[now];st[now]=1;if(now==i)break;}if(nowop==j)res++;}ans=(ans*res)%mod;}cout<<ans<<endl;}
signed main(){int t=1;//cin>>t;while(t--){solve();}
}