A String
题意:求s串1-i(1 <i <n)子串的贡献,贡献为公共前后缀相交并且相交部分长度为k的倍数的数量
题解做法是用exkmp求出s串与所有后缀的LCP后,设LCP为x,那么当x+i-1大于2*(i-1)时,有公共前后缀相交,而却会对2*(i-1)+k,2*(i-1)+2*k...等位置上有贡献,所以做个模意义上的差分。
还有一种做法是在kmp树上维护cnt[2*x%k],因为(2*x-len)%k==0,等价于2*x%k==len%k,计算答案时就是cnt[len%k],然后还要满足有相交的条件,可以在树链上二分查找(学长的做法),也可以用带限制的kmp求链顶。
比赛时没细想,原来还有exkmp比kmp方便的题,长见识
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
#define int long long
#define mem(x,y) memset(x,y,sizeof(x));
const int maxn=5e6+10;
const int mod=998244353;int n,k;
string s;
int z[maxn],f[maxn];void init()
{int l=1,r=0;for(int i=1;i<n;++i){int k=0;if(i<=r)k=min(z[i-l],r-i+1);while(i+k<n&&s[k]==s[i+k])++k;z[i]=k;if(i+k-1>r){l=i;r=i+k-1;}}
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);int _;cin>>_;while(_--){mem(f,0);cin>>s>>k;n=s.size();init();for(int i=0;i<n;++i){if(2*i-1+k<=i+z[i]-1)++f[2*i-1+k];else continue;int t=(i+z[i]-1-2*i+1)/k;--f[min(maxn,2*i-1+k*(t+1))];}// for(int i=0;i<n;++i)// cout<<f[i]<<" ";cout<<'\n';for(int i=0;i<n;++i)if(i-k>=0)f[i]+=f[i-k];for(int i=0;i<n;++i)if((i+1)%k==0)++f[i];int ans=1;for(int i=0;i<n;++i)ans=ans*(f[i]+1)%mod;cout<<ans<<'\n';}return 0;
}
B Dragon slayer
题意:地图上n堵墙,从起点到终点最少需要撞破多少堵
因为n最多只有15,所以直接bfs,并在每个位置打上 个标记,代表破了那堵墙,并优先更新破墙数少的状态
tips:可以把所有数×2避免处理double
比赛时,数组开大了,MLE了两发……
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
#define mem(x,y) memset(x,y,sizeof(x))
const int maxn=1<<16;
const int nx[4]={0,1,0,-1};
const int ny[4]={1,0,-1,0};struct Node
{int x,y;int sta,cnt=0;bool operator<(const Node &node)const{return cnt>node.cnt;}
};int n,m,k;
int sx,sy,tx,ty;
bool vis[16][16][maxn];
int a[35][35];int bfs()
{mem(vis,0);priority_queue<Node> q;Node it;it.x=2*sx+1;it.y=2*sy+1;it.sta=0;it.cnt=0;q.push(it);while(!q.empty()){Node fr=q.top();q.pop();if(vis[(fr.x-1)/2][(fr.y-1)/2][fr.sta])continue;vis[(fr.x-1)/2][(fr.y-1)/2][fr.sta]=1;if(fr.x==2*tx+1&&fr.y==2*ty+1)return fr.cnt;for(int i=0;i<4;++i){Node it=fr;int xx=fr.x+nx[i],yy=fr.y+ny[i];if(xx<=0||xx>=2*n||yy<=0||yy>=2*m)continue;if(a[xx][yy]&&((fr.sta>>a[xx][yy])&1)==0){it.sta|=(1<<a[xx][yy]);++it.cnt;}it.x+=2*nx[i];it.y+=2*ny[i];q.push(it);}}return -1;
}int main()
{ios::sync_with_stdio(0);cin.tie(0);int _;cin>>_;while(_--){mem(a,0);cin>>n>>m>>k;cin>>sx>>sy>>tx>>ty;int x1,y1,x2,y2;for(int i=1;i<=k;++i){cin>>x1>>y1>>x2>>y2;if(x1==x2){for(int j=2*min(y1,y2);j<=2*max(y1,y2);++j)a[2*x1][j]=i;}if(y1==y2){for(int j=2*min(x1,x2);j<=2*max(x1,x2);++j)a[j][2*y1]=i;}}cout<<bfs()<<'\n';}return 0;
}
C Backpack
题意:n个物品,m容量的背包,价值是异或和,求正好装满m的最大价值
dp[i][j]表示i答案j容量的状态能否到达,dp[i^v][j+w]=dp[i^v][j+w] | dp[i][j],这样是O()的,用bitset能优化到O( /32)
神奇的bitset
#include<iostream>
#include<bitset>
#include<cstring>
using namespace std;
#define mem(x,y) memset(x,y,sizeof(x))
const int maxn=1<<10;int n,m;
int v[maxn],w[maxn];
bitset<maxn> dp[2][maxn];int solve()
{mem(dp,0);dp[0][0][0]=1;int tot=0;for(int i=1;i<=n;++i){for(int j=0;j<(1<<10);++j)dp[tot^1][j]=dp[tot][j];for(int j=0;j<(1<<10);++j){dp[tot^1][j^v[i]]|=(dp[tot][j]<<w[i]);}tot^=1;}// for(int j=0;j<=14;++j)// {//     for(int i=0;i<=m;++i)//     cout<<dp[tot][i][j]<<" ";//     cout<<'\n';// }for(int j=(1<<10)-1;j>=0;--j)if(dp[tot][j][m])return j;return -1;
}int main()
{ios::sync_with_stdio(0);cin.tie(0);int _;cin>>_;while(_--){cin>>n>>m;for(int i=1;i<=n;++i)cin>>w[i]>>v[i];cout<<solve()<<'\n';}return 0;
}
D Ball
题意:有n个棋子,有几对三个棋子的曼哈顿距离的中位数是素数
可以预处理出所有棋子两两的曼哈顿距离,排序,然后每处理一条边,就打上标记,因为是完全图,所以如果当前的fr,to有一个点x,vis[fr][x],vis[to][x]其中有一个打了标记,那就以为着fr-x,to-x其中有一条边是大于fr-to的,一条边是小于fr-to的,也就是fr-to是中位数,所以只要是fr-to是素数,就统计答案,发现这个其实是异或,所以也可以用bitset优化
又是bitset
#include<iostream>
#include<bitset>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
#define debug(x) cout<<#x<<" "<<(x)<<endl
#define mem(x,y) memset(x,y,sizeof(x))
const int maxn=2e3+10;
const int maxm=3e5+10;struct Edge
{int fr,to,w;bool operator<(const Edge &edge)const{return w<edge.w;}
};int n,m;
int x[maxn],y[maxn];
Edge dis[maxn*maxn];
bitset<maxn> edg[maxn];
int tot=0,pi[maxn];
bool isp[maxm];void init()
{mem(isp,1);isp[1]=0;for(int i=2;i<maxm;++i){if(isp[i])pi[++tot]=i;for(int j=1;j<=tot&&i*pi[j]<maxm;++j){isp[i*pi[j]]=0;if(i%pi[j]==0)break;}}
}int solve()
{for(int i=1;i<=n;++i)edg[i].reset();int tot=0;for(int i=1;i<=n;++i)for(int j=1;j<i;++j)dis[++tot]={i,j,abs(x[i]-x[j])+abs(y[i]-y[j])};sort(dis+1,dis+1+tot);int ans=0;for(int i=1;i<=tot;++i){int fr=dis[i].fr,to=dis[i].to;if(isp[dis[i].w])ans+=(edg[fr]^edg[to]).count();edg[fr][to]=1;edg[to][fr]=1;}return ans;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);init();int _;cin>>_;while(_--){cin>>n>>m;for(int i=1;i<=n;++i)cin>>x[i]>>y[i];cout<<solve()<<'\n';}return 0;
}
H Path
题意:有一些特殊的边,在走过以后,走到相邻的点会值得花费-k,走到不相邻的点花费为0(好奇怪)
因为边权都是大于k的,没有负边权,所以跑dijkstra,每个点打两次标记,代表上次是不是特殊边,再用一个set维护还没有通过特殊边传送的点,因为这次传送肯定比下一次传送更优,所有对于每个点,传送只会更新一次,复杂度是可以接受的
可能题面有点奇怪,开的人不多
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
using namespace std;
#define debug(x) cout<<#x<<" "<<(x)<<endl
#define debug2(x,y) cout<<#x<<endl;for(int i=1;i<=y;++i)cout<<x[i]<<" ";cout<<endl
#define mem(x,y) memset(x,y,sizeof(x));
#define int long long
#define double long double
const int inf=0x3f3f3f3f3f3f3f3f;
const double eps=1e-9;
const double PI=acos(-1.0);
const int maxn=1e6+10;struct Edge
{int to,w,flg;bool operator<(const Edge &edge)const{return w>edge.w;}
};int n,m,s,k;
vector<Edge> edg[maxn];
bool vis[maxn][2];
int dis[maxn][2];
int dfn[maxn];void dijkstra()
{mem(vis,0);mem(dis,0x3f);mem(dfn,0);set<int> ss;for(int i=1;i<=n;++i)if(i!=s)ss.insert(i);priority_queue<Edge> q;dis[s][0]=0;q.push({s,0,0});int tot=0;while(!q.empty()){int fr=q.top().to,flg=q.top().flg;q.pop();if(vis[fr][flg])continue;vis[fr][flg]=1;ss.erase(fr);++tot;if(flg){for(auto it:edg[fr])dfn[it.to]=tot;vector<int> t;for(int it:ss){if(dfn[it]==tot)continue;dis[it][0]=dis[fr][1];q.push({it,dis[it][0],0});t.push_back(it);}for(int it:t)ss.erase(it);}int t=0;if(flg)t=k;for(auto it:edg[fr]){if(dis[it.to][it.flg]<dis[fr][flg]+it.w-t)continue;dis[it.to][it.flg]=dis[fr][flg]+it.w-t;q.push({it.to,dis[it.to][it.flg],it.flg});}}
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);// cout<<fixed<<setprecision(6);int _;cin>>_;while(_--){cin>>n>>m>>s>>k;for(int i=1;i<=n;++i)edg[i].clear();int fr,to,w,flg;for(int i=1;i<=m;++i){cin>>fr>>to>>w>>flg;edg[fr].push_back({to,w,flg});}dijkstra();for(int i=1;i<=n;++i){int t=min(dis[i][0],dis[i][1]);if(t!=dis[0][0])cout<<t<<" ";else cout<<-1<<" ";}cout<<'\n';}return 0;
}
I Laser
题面:有n个敌人,有一架米字炮,问能不能一次把所有敌人消灭
选两个点枚举他们在米字炮的哪两条边上,12种情况,还有在同一条线上的情况,那就再找第三个不在这条线上的点,3种情况
比赛时一开始的做法复杂了,写了一百五十几行才发现前面的检验都不需要,重写的时候也没想到怎么减少码量,总之体力被榨干了
#include<iostream>
using namespace std;
const int maxn=1e6+10;int n;
int x[maxn],y[maxn];bool check(int xx,int yy)
{for(int i=1;i<=n;++i){if(xx==x[i]||yy==y[i]||xx-yy==x[i]-y[i]||xx+yy==x[i]+y[i])continue;return 0;}return 1;
}bool big_check(int x1,int y1,int x2,int y2)
{int b1,b2;if(check(x2,y1))return 1;if(check(x2-(y1-y2),y1))return 1;if(check(x2+(y1-y2),y1))return 1;if(check(x1,y2))return 1;if(check(x1,y2-(x2-x1)))return 1;if(check(x1,y2+(x2-x1)))return 1;b1=y1-x1;if(check(y2-b1,y2))return 1;if(check(x2,x2+b1))return 1;b2=y2+x2;if(check((b2-b1)/2,(b1+b2)/2))return 1;b1=y1+x1;if(check(-y2+b1,y2))return 1;if(check(x2,-x2+b1))return 1;b2=y2-x2;if(check((b1-b2)/2,(b1+b2)/2))return 1;return 0;
}bool solve()
{if(n<=2)return 1;if(big_check(x[1],y[1],x[2],y[2]))return 1;int x1=x[1],y1=y[1],x2=x[2],y2=y[2];if(x1==x2){int t=-1;for(int i=3;i<=n;++i)if(x[i]!=x1)t=i;if(t==-1)return 1;else if(big_check(x1,y1,x[t],y[t]))return 1;}if(y1==y2){int t=-1;for(int i=3;i<=n;++i)if(y[i]!=y1)t=i;if(t==-1)return 1;else if(big_check(x1,y1,x[t],y[t]))return 1;}if(y1+x1==y2+x2){int t=-1;for(int i=3;i<=n;++i)if(y[i]+x[i]!=y1+x1)t=i;if(t==-1)return 1;else if(big_check(x1,y1,x[t],y[t]))return 1;}if(y1-x1==y2-x2){int t=-1;for(int i=3;i<=n;++i)if(y[i]-x[i]!=y1-x1)t=i;if(t==-1)return 1;else if(big_check(x1,y1,x[t],y[t]))return 1;}return 0;
}int main()
{ios::sync_with_stdio(0);cin.tie(0);int _;cin>>_;while(_--){cin>>n;for(int i=1;i<=n;++i){cin>>x[i]>>y[i];x[i]*=2;y[i]*=2;}if(solve())cout<<"YES\n";else cout<<"NO\n";}return 0;
}
K Random
题意:有n个0到1的随机数,删除m个数,1/2概率删除最大值,1/2概率删除最小值
n个数的期望是0.5,因为一半概率删最大,一半概率删最小,所以期望还是0.5,剩下n-m个数,答案就是(n-m)/2,再求一下逆元
#include<iostream>
#include<cstring>
using namespace std;
#define int long long
#define debug(x) cout<<#x<<": "<<(x)<<endl
#define mem(x,y) memset(x,y,sizeof(x))
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;int bitpow(int x,int y)
{int res=1;while(y){if(y&1)res=res*x%mod;x=x*x%mod;y>>=1;}return res;
}signed main()
{ios::sync_with_stdio(0);cin.tie(0);int _;cin>>_;int inv2=bitpow(2,mod-2);while(_--){int x,y;cin>>x>>y;cout<<(x-y+mod)*inv2%mod<<'\n';}return 0;
}
L Alice and Bob
题面:有一些数,Alice分成两堆,Bob选一堆删除,另一堆所有数-1,场上有0Alice就赢,问谁赢
2个1或者4个2或者……可以赢,然后一个数等价于前面的半个数
博弈论不太懂,反正交给队友了,因为队友太强了
#include<iostream>
using namespace std;
#define int long long
const int maxn=1e6+10;int n;
int a[maxn];signed main()
{ios::sync_with_stdio(0);cin.tie(0);int _;cin>>_;while(_--){cin>>n;for(int i=0;i<=n;++i)cin>>a[i];bool flg=0;for(int i=n;i>=0;--i){if(a[i]>>i){flg=1;break;}if(i)a[i-1]+=a[i]/2;}if(flg)cout<<"Alice\n";else cout<<"Bob\n";}return 0;
}

2022杭电多校第一场相关推荐

  1. 2022 杭电多校 第一场

    文章目录 1011 Random 1012 Alice and Bob 1003 Backpack 1002 Dragon slayer 1009 Laser 1011 Random 签到 求一下期望 ...

  2. 2019年杭电多校第一场 1001题blank(DP)HDU6578

    2019年杭电多校第一场 1001题blank(DP)HDU6578 解决思路,开一个DP数组来存储0 1 2 3四个字符最后出现的位置,并且在DP中已经==排好序==. DP开四维,DP[i][j] ...

  3. 2022“杭电杯”中国大学生算法设计超级联赛 (1) 杭电多校第一场 2 3 4 5 8 12

    题目 1002 Dragon slayer 标程 1003 Backpack AC代码 1004 Ball AC代码 1008 Path AC代码 1009 Laser AC代码 1012 Alice ...

  4. 杭电多校第一场第三题 Backpack(异或dp+bitset)

    问题描述 爱丽丝有一个容量背包m她现在想用一些物品填充! 爱丽丝有n项目,每个项目都有一个卷v我和值w我. 是否可以从n个项目中选择多个项目,以使背包完全装满(即体积的总和等于背包容量)?如果是这样, ...

  5. 2019杭电多校第一场 Operation HDU - 6579

    题意:给出一个序列,两种操作,求区间[l,r]的区间最大异或和,和在末尾添加一个数 思路:强制在线,保存每个线性基的数值,接下去直接去搜第r个线性基,但要保持时间比l要大,新增了一个pos数组代表一个 ...

  6. HDU-6578 Blank(DP)2019暑假杭电多校第一场

    题意:一行有n个空格编号1~n; 每一个空格中填入0,1,2,3中的一个数字.且满足m个限制l,r,x:满足在区间[l,r]正好有x种不同的数字. 有多少种方法可以填充空格以满足所有条件? 思路:dp ...

  7. 2019杭电多校第一场 HDU 6599

    题解 枚举所有的回文串 注意,本质不同的回文串最多只有∣S∣|S|∣S∣个 在这些回文串中,有一些是满足要求的,我们对这些串打上标记 首先跑一个ManacherManacherManacher,然后枚 ...

  8. 2022杭电多校第二场

    1001 Static Query on Tree 题意:树上有A,B,C三个集合,求有多少个点在A某个点到C某个点的路径与A某个点到C某个点的路径的交上 把1到A集合中所有点的路径打上标记1,把1到 ...

  9. 2022杭电多校(一)

    2022杭电多校(一) 文章目录 2022杭电多校(一) 一.比赛小结 二.题目分析及解法(基础题) 1001.String 1002.Dragon slayer 1003.BackPack 1004 ...

最新文章

  1. 如何判断强化学习训练是否在收敛?
  2. 反积分饱和 程序_非常通俗易懂的PID控制(2)--积分饱和
  3. android studio页面布局代码,还在用Android正经布局来写页面吗?
  4. GPS NMEA0183协议解析(转载)
  5. PHP与Javascript的混合测试
  6. Centos上安装jdk版本出错的问题
  7. jQuery UI =jquery-ui.js中sortable方法拖拽对象位置偏移问题
  8. LINUX下多路径(multi-path)介绍及使用
  9. ecg 幅度_用ECG和PPG测血压靠谱吗?有什么比较好的算法?
  10. 我的世界光影Java优化_我的世界7款超级棒的光影包推荐 让你的世界从此变得真实无比...
  11. 抽签小程序,妈妈再也不用担心谁洗碗(分配任务)了,so easy
  12. 磁共振t1t2信号记忆顺口溜_核磁共振诊断报告中的T1T2信号是什么意思?
  13. 学会理解和更新kali软件源
  14. 程序员需知的9个编程学习官网,建议收藏
  15. Countdownlatch、CyclicBarrier、join区别
  16. 客户 服务器协议简写,客户端和服务器端的简写
  17. 进军元宇宙,Akutars是什么来头?首发与众多知名潮牌联名
  18. HttpRestful工具类
  19. 【CEGUI】CEGUI入门篇之数据文件及默认初始化(三)
  20. UG NX 12 对象选择

热门文章

  1. 服务器安装系统——出错BUG: soft lockup...
  2. leetcode 23. 合并K个排序链表
  3. ModelCheckpoint自动保存模型
  4. postman传参后乱码
  5. [转]WCF 4 安全性和 WIF 简介
  6. 三毛最伤心的一百句话
  7. NBA历史上50大巨星1
  8. IIS应用程序池启用32位导致服务不可用的503错误
  9. java知识汇总—思维导图
  10. 【计量模型整理】偏最小二乘回归 PLS