2021 杭电多校/中超 第八场记录
1003-Ink on paper
队友写的prim,本题数据卡克鲁斯卡尔
#include<bits/stdc++.h> using namespace std; typedef long long ll; int n; ll x[5005],y[5005]; int cnt,father[5005],vis[50005],cnt2=1; ll g[5005][5005]; ll dis[5005]; void prim() { for(int i=1;i<=n;i++){ dis[i]=9*1e18; vis[i]=0; } dis[1]=0; for(int j=1;j<=n;j++) { ll min_len=9*1e18; int k; for(int i=1;i<=n;i++) { if(!vis[i]&&dis[i]<min_len) { min_len=dis[i]; k=i; } } vis[k]=1; for(int i=1;i<=n;i++) { if(!vis[i]&&dis[i]>g[k][i]) dis[i]=g[k][i]; } } } int main(){ int t; cin>>t; while(t--){ cin>>n; cnt=0; cnt2=1; for(int i=1;i<=n;i++) father[i]=i; for(int i=1;i<=n;i++){ scanf("%lld %lld",&x[i],&y[i]); } for(int i=1;i<=n;i++){ //关键代码 for(int j=i+1;j<=n;j++){ g[i][j]=g[j][i]=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); } } ll ans=0; prim(); for(int i=1;i<=n;i++) ans=max(ans,dis[i]); printf("%lld\n",ans); } return 0; }
1006-GCD Game
素因子个数当成石子数就好,然后预处理利用一下线性筛拆分的思想。
int x,res[10000007],n; bool isPrime[10000007]; int Prime[10000007], cnt = 0; void GetPrime(int n){ memset(isPrime, 1, sizeof(isPrime)); isPrime[0] = 0;isPrime[1] = 0; for(int i = 2; i <= n; i++){ if(isPrime[i]){ Prime[++cnt] = i; res[i]=1; } for(int j = 1; j <= cnt && i*Prime[j] <= n; j++) { isPrime[i*Prime[j]] = 0; res[i*Prime[j]]=res[i]+res[Prime[j]]; if(i % Prime[j] == 0) break; } } } void solve(){ scanf("%d",&n); int ans=0; for(int i=1;i<=n;++i){ scanf("%d",&x); ans=ans^res[x]; } if(ans==0) printf("Bob\n"); else printf("Alice\n"); }
1009-Singing Superstar
多个模式串匹配,ac自动机板子题,现场学的ac自动机。
标记上一个满足条件的位置,判断是否重复。
标记相同模式串编号
const int N = 1e5+5,M=6e5+5; char s[N],str[N][100]; int fail[M],cnt[N],last[N],vis[N],tail[M],n; int ch[N][30],idx,tot; void insert(char *str,int id){ int cur=0; for(int i=0;str[i];++i){ int idx=str[i]-'a'; if(!ch[cur][idx]) ch[cur][idx]=++tot; cur=ch[cur][idx]; } if(tail[cur]==0){//标记字符串结尾 tail[cur]=id;//结尾标记返回编号 } else{ vis[id]=tail[cur];//重复标记返回先前位置 } } void build(){ queue<int> q; for(int j=0;j<26;++j) if(ch[0][j]) q.push(ch[0][j]); while(!q.empty()){ int now=q.front(); q.pop(); for (int j=0;j<26;j++){ if(ch[now][j]){ fail[ch[now][j]]=ch[fail[now]][j]; q.push(ch[now][j]); } else{ ch[now][j]=ch[fail[now]][j]; } } } } void solve(){ tot=0; memset(ch,0,sizeof(ch)); memset(fail,0,sizeof(fail)); memset(cnt,0,sizeof(cnt)); memset(vis,0,sizeof(vis)); memset(tail,0,sizeof(tail)); memset(last,-1,sizeof(last)); scanf("%s",s); scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%s",str[i]); insert(str[i],i); } build(); int cur=0; for(int i=0;s[i];++i){ int idx=s[i]-'a'; cur=ch[cur][idx]; int tmp=cur; while(tmp){//当前节点 if(tail[tmp]){ int flag=i-last[tail[tmp]]-strlen(str[tail[tmp]]); if(flag>=0){ cnt[tail[tmp]]++, last[tail[tmp]] = i; } } tmp=fail[tmp]; } } for(int i=1;i<=n;++i){ if(vis[i]) printf("%d\n",cnt[vis[i]]);//重复情况 else printf("%d\n",cnt[i]);//不重 } }
1004-Counting Stars
操作1,区间求和 操作2 区间减lowbit(ai) 操作3 区间加2^k(2^k <= ai <= 2^(k+1))
区间减去lowbit(ai),就是减去最低位1,对于某一个数ai最多操作log(ai)次,可以暴力维护 时间复杂度 nlognlogn
当区间都置为0,不去操作,考虑一个零标记
区间加2^k 就是最高位前移一位 ,考虑单独维护最高位*2
#include<bits/stdc++.h> #define inf 1e18 #define int long long #define ull unsigned long long #define PI acos(-1.0) using namespace std; const int N = 1e5+5; const int mod=998244353; int n,x,q; int a1[N],a2[N],s1[N<<2],s2[N<<2],tag[N<<2],lazy[N<<2]; int lowbit(int x){ return x&(-x); } void pushup(int o){ s1[o]=(s1[o<<1]+s1[o<<1|1])%mod;//最高位 s2[o]=(s2[o<<1]+s2[o<<1|1])%mod;//其他位 tag[o]=tag[o<<1]&tag[o<<1|1];//零标记位 } void pushdown(int o){ lazy[o<<1]=lazy[o<<1]*lazy[o]%mod; lazy[o<<1|1]=lazy[o<<1|1]*lazy[o]%mod; s1[o<<1]=s1[o<<1]*lazy[o]%mod; s1[o<<1|1]=s1[o<<1|1]*lazy[o]%mod; tag[o<<1]=tag[o<<1]|tag[o]; tag[o<<1|1]=tag[o<<1|1]|tag[o]; if(tag[o<<1]) s2[o<<1]=0; if(tag[o<<1|1]) s2[o<<1|1]=0; lazy[o]=1; } void build(int o,int l,int r){ lazy[o]=1;//首位乘法的lazy标记 tag[o]=0;//零标记 if(l==r){ s1[o]=a1[l],s2[o]=a2[l]; return ; } int mid=l+r>>1; build(o<<1,l,mid); build(o<<1|1,mid+1,r); pushup(o); } int query(int o,int l,int r,int ll,int rr){ if(ll<=l&&rr>=r){ return (s1[o]+s2[o])%mod; } pushdown(o); int mid=l+r>>1; int ans=0; if(ll<=mid) ans=(ans+query(o<<1,l,mid,ll,rr))%mod; if(rr>mid) ans=(ans+query(o<<1|1,mid+1,r,ll,rr))%mod; return ans%mod; } void upd1(int o,int l,int r,int ll,int rr){ if(l==r){//对单点暴力操作最多logn if(s2[o]){//当前点还有位可以减去 s2[o]=s2[o]-lowbit(s2[o]); } else{ s1[o]=0;//减掉最高位 tag[o]=1;//说明当前点为0 } return ; } pushdown(o); int mid=l+r>>1; if(ll<=mid&&!tag[o<<1]) upd1(o<<1,l,mid,ll,rr); if(rr>mid&&!tag[o<<1|1]) upd1(o<<1|1,mid+1,r,ll,rr); pushup(o); } void upd2(int o,int l,int r,int ll,int rr){ if(ll<=l&&rr>=r){ s1[o]=s1[o]*2%mod; lazy[o]=lazy[o]*2%mod; return ; } pushdown(o); int mid=l+r>>1; if(ll<=mid) upd2(o<<1,l,mid,ll,rr); if(rr>mid) upd2(o<<1|1,mid+1,r,ll,rr); pushup(o); } void solve(){ scanf("%lld",&n); for(int i=1;i<=n;++i){ scanf("%lld",&x); for(int j=31;j>=0;--j){ int idx=(1ll<<j); if(idx<=x){//找最高位 a1[i]=idx; a2[i]=x-idx; break; } } } build(1,1,n); scanf("%lld",&q); while(q--){ int op,l,r; scanf("%lld%lld%lld",&op,&l,&r); if(op==1){//求和 int ans=query(1,1,n,l,r); printf("%lld\n",ans); } else if(op==2){//减去lowbit upd1(1,1,n,l,r); } else{//最高位加 upd2(1,1,n,l,r); } } } signed main(){ int t=1; scanf("%lld",&t); while(t--){ solve(); } return 0; }