A.
直接把1e6的质数筛出来
然后枚举每一位即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N = 5e6+10;
typedef pair<int, int> PII;
int primes[N],cnt;
bool st[N];
int n;
int a[N];
void count(int n){
for(int i=2;i<=n;i++){
if(!st[i]) primes[cnt++]=i,a[i]=1;
for(int j=0;i<=n/primes[j];j++){
st[i*primes[j]]=true;
if(i%primes[j]==0) break;
}
}
}
void solve(){
string s;
cin>>s;
int x=0;
for(int i=0;i<s.size();i++){
x=x*10+(s[i]-'0');
if(!a[x]){
cout<<"NO\n";
return ;
}
}
cout<<"YES\n";
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
count(1000010);
while(t--) solve();
}
B.
有两个结论
就30个二进制位有一个0当前位最终&值就肯定是0
只要你 l到r的与是0,那么[1,i-1]到r也同样是0
直接预处理前面的数每个二进制位存在0的最大的位置
然后以i为右端点,找a[i]二进制为1的位数,因为a[i]为1,那么前面一定要存在一个0
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N = 1e6+10;
typedef pair<int, int> PII;
int a[N];
int n,m;
int cnt[N][31];
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
long long res=0;
int now=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=30;j++)
if(((a[i]>>j)&1)==0) cnt[i][j]=i;
else cnt[i][j]=cnt[i-1][j];
}
for(int i=1;i<=n;i++)
{
int mx=i;
for(int j=0;j<=30;j++)
{
if(a[i]>>j&1){
mx=min(mx,cnt[i][j]);
}
}
res+=mx;
}
cout<<res;
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
while(t--) solve();
}
C.
就是求最长公共子序列即可
公共子序列是不用动的,其他数插入进来即可,也不改变顺序
因为是一个全排列
可以把a离散化
然后最后求b的最长上升子序列即可
比如
A=1 2 3 4 5 6
B=6 3 4 5 12
求b的最长上升子序列
# include <iostream>
# include <vector>
# include <map>
using namespace std;
const int maxn = 1e6 + 10;
int n;
map<int, int>m;
int B[maxn];
int main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
cin >> n;
int a;
for (int i = 1; i <= n; i++) {
cin >> a;
m[a] = i;
}
int b;
for (int i = 1; i <= n; i++) {
cin >> b;
B[i] = m[b];
}
vector<int>C;
C.push_back(0);
int len = 0;
for (int i = 1; i <= n; i++) {
if (B[i] > C[len]) {
C.push_back(B[i]);
len++;
}
else {
C[lower_bound(C.begin(), C.end(), B[i]) - C.begin()] = B[i];
}
}
cout << n-len << endl;
return 0;
}
D.
这个题是最短路毕竟是求最短时间0.0
这个题是从开头点(不是出发点)出发,每t秒开一次
为了方便我们存图的时候记录距离开头点和当前点中间相差多少个站(i-1,可能有人疑惑???,解释一下,因为是求开头点到当前点最短路所以当前点还没到,有效距离是不算当前站点的)
然后直接dijkstra,然后计算上一个开头点和当前点的时间和k*t的差即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
#define int long long
typedef pair<int, int> PII;
using node=tuple<int,int,int> ;
int n,m,s;
vector<node> g[N];
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
cin>>n>>m>>s;
for(int i=0;i<m;i++){
int k,t;cin>>k>>t;
vector<int> c(k);
for(auto&x:c) cin>>x;
for(int i=1;i<k;i++){
g[c[i-1]].emplace_back(c[i],t,i-1);
}
}
vector<int> d(n+1,-1);
priority_queue<PII,vector<PII>,greater<PII>> q;
q.push({d[s]=0,s});
while(q.size()){
auto p=q.top();
q.pop();
int u=p.second;
if(p.first>d[u]) continue;
for(auto [v,t,ed]:g[u]){
int w;
if(ed>=d[u])
{
w=ed+1;
}
else
{
w=(d[u]-ed+t-1)/t*t+ed+1;
}
if(d[v]==-1||d[v]>w)
{
q.push({d[v]=w,v});
}
}
}
for(int i=1;i<=n;i++) cout<<d[i]<<"\n";
}
E.
把绝对值拆开,然后分类讨论即可
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
struct Node {
LL x, y, id;
} t[5][N];
bool cmp1(Node a, Node b) {
if (a.x + a.y != b.x + b.y)
return a.x + a.y < b.x + b.y;
return a.id < b.id;
}
bool cmp2(Node a, Node b) {
if (a.x + a.y != b.x + b.y)
return a.x + a.y > b.x + b.y;
return a.id < b.id;
}
bool cmp3(Node a, Node b) {
if (a.x - a.y != b.x - b.y)
return a.x - a.y < b.x - b.y;
return a.id < b.id;
}
bool cmp4(Node a, Node b) {
if (a.x - a.y != b.x - b.y)
return a.x - a.y > b.x - b.y;
return a.id < b.id;
}
bool vis[N];
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
int x, y;
cin >> x >> y;
for (int j = 1; j <= 4; ++j)
t[j][i] = {x, y, i};
}
sort(t[1] + 1, t[1] + 1 + n, cmp1);
sort(t[2] + 1, t[2] + 1 + n, cmp2);
sort(t[3] + 1, t[3] + 1 + n, cmp3);
sort(t[4] + 1, t[4] + 1 + n, cmp4);
int p[5];
for (int i = 1; i <= 4; ++i)
p[i] = 1;
LL x = 0, y = 0;
LL ans = 0;
for (int k = 1; k <= n; ++k) {
LL dis = -1, re;
for (int i = 1; i <= 4; ++i) {
while (p[i] <= n && vis[t[i][p[i]].id]) {
++p[i];
}
if(i==1){
LL tmp=x+y-(t[i][p[i]].x+t[i][p[i]].y);
tmp=abs(tmp);
if(tmp>dis){
dis=tmp;
re=i;
}
else if(tmp==dis&&t[re][p[re]].id>t[i][p[i]].id){
re=i;
}
}
if(i==2){
LL tmp=-x-y+(t[i][p[i]].x+t[i][p[i]].y);
tmp=abs(tmp);
if(tmp>dis){
dis=tmp;
re=i;
}
else if(tmp==dis&&t[re][p[re]].id>t[i][p[i]].id){
re=i;
}
}
if(i==3){
LL tmp=x -y - (t[i][p[i]].x - t[i][p[i]].y);
tmp=abs(tmp);
if(tmp>dis){
dis=tmp;
re=i;
}
else if(tmp==dis&&t[re][p[re]].id>t[i][p[i]].id){
re=i;
}
}
if(i==4){
LL tmp=-x + y + (t[i][p[i]].x - t[i][p[i]].y);
tmp=abs(tmp);
if(tmp>dis){
dis=tmp;
re=i;
}
else if(tmp==dis&&t[re][p[re]].id>t[i][p[i]].id){
re=i;
}
}
}
ans += dis;
x = t[re][p[re]].x;
y = t[re][p[re]].y;
vis[t[re][p[re]].id] = 1;
}
cout << ans << '\n';
}
int main() {
// freopen("a.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin>>t;
while (t--) {
solve();
}
return 0;
}
F.
换根dp
看范围油费<=50
状态设置为g2以u为根,最低油费为k的油费总和
g1就是以u为根到每个儿子节点路径中最低油费为k的节点个数
f1同理
第一次dfs
如果k<c[u],正常转移到k即可
但如果c[u]>k,那么只能全部转移到c[u],因为这个路径最小的肯定只有u,一定包含根节点
这个时候先考虑不用c[u]这个加油站,先用子树里面最小的加油站
第二次dfs换根
首先要加上父节点子树上面的价值,同时又因为父节点子树包含了自己,但是自己又已经有自己,所以要(f1[u][k] - g1[j][k]) * w[i] * k减去多了的自己总和
最后考虑c[u]父节点这个加油站,把前面大于c[u]且不考虑的加油站全去掉
改用c[u]这个更小的加油站
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10, M = 1e6 + 10;
LL f1[N][51], f2[N][51], g1[N][51], g2[N][51];
int c[N];
int h[N], w[M], e[M], ne[M], idx;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dfs1(int u, int fa) {
g1[u][c[u]]++;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == fa)
continue;
dfs1(j, u);
for (int k = 1; k <= 50; ++k) {
if (k < c[u]) {
g1[u][k] += g1[j][k];
g2[u][k] += g2[j][k] + g1[j][k] * k * w[i];
} else {
g1[u][c[u]] += g1[j][k];
g2[u][c[u]] += g2[j][k] + g1[j][k] * k * w[i];
}
}
}
}
void dfs2(int u, int fa) {
for (int k = 1; k <= 50; ++k) {
f1[u][k] += g1[u][k];
f2[u][k] += g2[u][k];
}
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == fa)
continue;
for (int k = 1; k < c[u]; ++k) {
f1[j][min(c[j], k)] += f1[u][k] - g1[j][k];
f2[j][min(c[j], k)] += f2[u][k] - (g2[j][k] + g1[j][k] * k * w[i])
+ (f1[u][k] - g1[j][k]) * w[i] * k;
}
LL s1 = f1[u][c[u]], s2 = f2[u][c[u]];
for (int k = c[u]; k <= 50; ++k) {
s2 -= g2[j][k] + k * w[i] * g1[j][k];
s1 -= g1[j][k];
}
f1[j][min(c[j], c[u])] += s1;
f2[j][min(c[j], c[u])] += s2 + s1 * w[i] * c[u];
dfs2(j, u);
}
}
void solve() {
int n;
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i <= n; ++i)
cin >> c[i];
for (int i = 1; i <= n - 1; ++i) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
dfs1(1, 0);
dfs2(1, 0);
LL ans = 0;
for (int i = 1; i <= n; ++i) {
for (int k = 1; k <= 50; ++k) {
ans += f2[i][k];
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin>>t;
while (t--) {
solve();
}
return 0;
}