2017 多校联合训练 5 题解
Problem 1001
先预处理出一个数组,记录每个数对(x,y),y是x的倍数
用一个bitset A把a数组记录下来
然后用一个数组统计b数组
再用s数组维护一个后缀,s[x]表示大于x所有出现的数的个数的奇偶性
然后对于每一个未出现过的询问k,每个b数组中有的大于k的数,用bitset B记录它的倍数出现数的奇偶性
最后答案为(A>>k)&B中1的奇偶行与s[k+1]的异或值
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 #include<bitset> 13 using namespace std; 14 const int inf=(1<<30)-1; 15 const int maxn=50010; 16 #define REP(i,n) for(int i=(0);i<(n);i++) 17 #define FOR(i,j,n) for(int i=(j);i<=(n);i++) 18 typedef long long ll; 19 typedef pair<int,int> PII; 20 int IN(){ 21 int c,f,x; 22 while (!isdigit(c=getchar())&&c!='-');c=='-'?(f=1,x=0):(f=0,x=c-'0'); 23 while (isdigit(c=getchar())) x=(x<<1)+(x<<3)+c-'0';return !f?x:-x; 24 } 25 #define MP make_pair 26 #define fi first 27 #define se second 28 int n,m,q; 29 int a[maxn],b[maxn],tot,k,ans[maxn]; 30 bitset<maxn> A,B,tmp; 31 32 PII cnt[maxn*20]; 33 PII t[maxn]; 34 35 void init() 36 { 37 tot=0; 38 for(int i=maxn-5;i>=1;i--) 39 for(int j=i;j<=maxn-5;j+=i) 40 cnt[++tot]=MP(i,j); 41 } 42 bool cmp(const PII &x,const PII & y) {return x.fi>y.fi;} 43 bool vis[maxn],s[maxn]; 44 int main(){ 45 init(); 46 int T;scanf("%d",&T); 47 while(T--) 48 { 49 A.reset(); 50 B.reset(); 51 memset(vis,0,sizeof(vis)); 52 memset(s,0,sizeof(s)); 53 n=IN();m=IN();q=IN(); 54 for(int i=1;i<=n;i++) 55 a[i]=IN(),A[a[i]]=1; 56 for(int i=1;i<=m;i++) 57 b[i]=IN(),vis[b[i]]=1; 58 for(int i=50000;i>=0;i--) 59 s[i]=vis[i+1]^s[i+1]; 60 for(int i=1;i<=q;i++) 61 t[i].fi=IN(),t[i].se=i; 62 sort(t+1,t+q+1,cmp); 63 int p=1; 64 for(int i=1;i<=q;i++) 65 { 66 int k=t[i].fi; 67 if(i>1&&k==t[i-1].fi) { 68 ans[t[i].se]=ans[t[i-1].se]; 69 continue; 70 } 71 for(;p<=tot&&cnt[p].fi>k;p++) 72 if(vis[cnt[p].fi]) 73 { 74 B[cnt[p].se]=B[cnt[p].se]^1; 75 //cout<<vis[cnt[p]].se<<" "<<vis[cnt[p]].fi<<endl; 76 } 77 tmp=A>>k; 78 tmp&=B; 79 ans[t[i].se]=(tmp.count()&1); 80 if(A[k]) ans[t[i].se]^=s[k]; 81 } 82 for(int i=1;i<=q;i++) printf("%d\n",ans[i]); 83 } 84 return 0; 85 }
Problem 1002
如果没有反字符串的限制,那么是一道经典的AC自动机
预处理所有正串和反串的AC自动机
从中间向两边dp
然后暴力枚举从中间向左右的字符
统计哪些串已经出现过
这时可以暴力枚举dp的初始值
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 using namespace std; 13 struct node 14 { 15 int next[2]; 16 int fail,flag; 17 /*void init() 18 { 19 memset(next,0,sizeof(next)); 20 fail=0; 21 flag=0; 22 }*/ 23 } trie[200],T[200]; 24 int tot; 25 void init() 26 { 27 tot=0; 28 memset(trie,0,sizeof(trie)); 29 } 30 void insert(char *str,int val) 31 { 32 int p=0,index,i,l=strlen(str); 33 for (i=0;i<l;i++) 34 { 35 index=str[i]-'0'; 36 if (trie[p].next[index]==0) 37 { 38 trie[p].next[index]=++tot; 39 //cout<<"hhhhhhh"<<endl; 40 } 41 p=trie[p].next[index]; 42 } 43 trie[p].flag|=(1<<val); 44 } 45 int go[2][200][2],w[2][200]; 46 void build_fail(int pd) 47 { 48 queue<int> Q; 49 /*int i; 50 for (i=0;i<2;i++) 51 if (trie[0].next[i]) 52 Q.push(trie[0].next[i]); 53 while (!Q.empty()) 54 { 55 int k=Q.front(); 56 trie[k].flag|=trie[trie[k].fail].flag; 57 for (i=0;i<2;i++) 58 { 59 int j=trie[k].next[i]; 60 if (j==0) trie[k].next[i]=trie[trie[k].fail].next[i]; 61 else 62 { 63 trie[j].flag|=trie[k].flag; 64 trie[j].fail=trie[trie[k].fail].next[i]; 65 Q.push(j); 66 } 67 } 68 Q.pop(); 69 }*/ 70 int p,son,cur,i; 71 Q.push(0); 72 while (!Q.empty()) 73 { 74 p=Q.front(); 75 Q.pop(); 76 for (i=0;i<2;i++) 77 { 78 if (trie[p].next[i]!=0) 79 { 80 son=trie[p].next[i]; 81 cur=trie[p].fail; 82 if (p==0) 83 trie[son].fail=0; 84 else 85 { 86 while (cur&&trie[cur].next[i]==0) 87 cur=trie[cur].fail; 88 trie[son].fail=trie[cur].next[i]; 89 } 90 trie[son].flag=trie[son].flag|trie[trie[son].fail].flag; 91 Q.push(son); 92 } 93 else 94 { 95 trie[p].next[i]=trie[trie[p].fail].next[i]; 96 } 97 } 98 } 99 for (i=0;i<=tot;i++) 100 { 101 go[pd][i][0]=trie[i].next[0]; 102 go[pd][i][1]=trie[i].next[1]; 103 w[pd][i]=trie[i].flag; 104 } 105 if (pd==0) memcpy(T,trie,sizeof(trie)); 106 } 107 const int mo=998244353; 108 int _,n,L; 109 char s[11][31]; 110 int dp[2][70][130][130]; 111 void upd(int &x,int y) 112 { 113 x=(x+y)%mo; 114 } 115 int main() 116 { 117 scanf("%d",&_); 118 while (_--) 119 { 120 init(); 121 scanf("%d%d",&n,&L); 122 int i,j,k1,k2,k,len1,len2; 123 for (i=1;i<=n;i++) 124 { 125 scanf("%s",s[i]); 126 insert(s[i],i-1); 127 } 128 build_fail(0); 129 len1=tot; 130 init(); 131 for (i=1;i<=n;i++) 132 { 133 int l=strlen(s[i]); 134 for (j=0;j<l;j++) 135 if (l-j-1>j) swap(s[i][j],s[i][l-j-1]); 136 } 137 for (i=1;i<=n;i++) 138 insert(s[i],i-1); 139 build_fail(1); 140 len2=tot; 141 for (i=1;i<=n;i++) 142 { 143 int l=strlen(s[i]); 144 for (j=0;j<l;j++) 145 if (l-j-1>j) swap(s[i][j],s[i][l-j-1]); 146 } 147 memset(dp,0,sizeof(dp)); 148 int l=0; 149 for (i=1;i<=n;i++) 150 l=max(l,(int)strlen(s[i])); 151 l=min(l,L); 152 for (int W=0;W<(1<<l);W++) 153 { 154 int now=0,pd=0; 155 for (i=0;i<l;i++) 156 { 157 int k=((W&(1<<i))>0); 158 now=trie[now].next[k]; 159 pd|=trie[now].flag; 160 } 161 for (i=l-1;i>=0;i--) 162 { 163 int k=((W&(1<<i))==0); 164 now=trie[now].next[k]; 165 pd|=trie[now].flag; 166 } 167 int k1=now; 168 now=0; 169 for (i=l-1;i>=0;i--) 170 { 171 int k=((W&(1<<i))>0); 172 now=T[now].next[k]; 173 } 174 dp[0][pd][now][k1]++; 175 //cout<<0<<" "<<pd<<" "<<now<<" "<<k1<<endl; 176 } 177 int now=0; 178 for (i=l+1;i<=L;i++) 179 { 180 int nex=now^1; 181 int W=0; 182 memset(dp[nex],0,sizeof(dp[nex])); 183 for (j=0;j<(1<<n);j++) 184 for (k1=0;k1<=len1;k1++) 185 for (k2=0;k2<=len2;k2++) 186 if (W=dp[now][j][k1][k2]) 187 for (k=0;k<2;k++) 188 { 189 int k3=T[k1].next[k],k4=trie[k2].next[k^1]; 190 upd(dp[nex][j|T[k3].flag|trie[k4].flag][k3][k4],W); 191 } 192 now=nex; 193 } 194 int ans=0; 195 for (i=0;i<=len1;i++) 196 for (j=0;j<=len2;j++) 197 upd(ans,dp[now][(1<<n)-1][i][j]); 198 printf("%d\n",ans); 199 } 200 return 0; 201 }
Problem 1006
m<n时连成一个菊花图
m>=n时,剩下的每一条边将每一对点的距离缩减为1
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 8 typedef long long LL; 9 int T; 10 LL n, m; 11 LL ans; 12 13 int main(){ 14 15 16 scanf("%d", &T); 17 while (T--){ 18 scanf("%lld%lld", &n, &m); 19 LL ans = n*n*n - n*n; 20 21 LL dx = (n - 1) * 2; 22 LL dy = dx - 2; 23 24 if (m >= n){ 25 LL op = m; 26 rep(i, 1, n - 1){ 27 ans -= dx; 28 dx += dy; 29 } 30 31 LL yy = m - (n - 1); 32 ans -= yy * 2; 33 34 ans = max(ans, n * (n - 1)); 35 printf("%lld\n", ans); 36 37 38 } 39 40 else{ 41 rep(i, 1, m){ 42 ans -= dx; 43 dx += dy; 44 } 45 46 ans = max(ans, n * (n - 1)); 47 48 printf("%lld\n", ans); 49 }
Problem 1008
从前往后枚举
把缺的数补完整即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cstring> 7 #include<string> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #include<queue> 12 using namespace std; 13 typedef long long ll; 14 int _,n,m; 15 ll b[10010],now[10010],a[10010],as[10010],p[10010]; 16 ll C[61][61]; 17 void init() 18 { 19 int i,j; 20 for (i=0;i<=50;i++) 21 { 22 C[i][0]=1; 23 C[i][i]=1; 24 } 25 for (i=1;i<=50;i++) 26 for (j=1;j<=50;j++) 27 C[i][j]=C[i-1][j]+C[i-1][j-1]; 28 } 29 int main() 30 { 31 init(); 32 scanf("%d",&_); 33 while (_--) 34 { 35 scanf("%d%d",&n,&m); 36 int i,j,k; 37 for (i=0;i<=m;i++) 38 scanf("%lld",&b[i]); 39 memset(now,0,sizeof(now)); 40 memset(a,0,sizeof(a)); 41 memset(p,0,sizeof(p)); 42 int t=0,tt=0; 43 //cout<<b[0]<<" "<<now[1]<<endl; 44 now[0]=1; 45 for (i=1;i<=m;i++) 46 { 47 //cout<<i<<" "<<b[i]<<" "<<now[i]<<endl; 48 if (now[i]<b[i]) 49 { 50 a[i]=b[i]-now[i]; 51 //cout<<i<<" "<<now[6]<<endl; 52 tt+=a[i]; 53 if (tt==n) break; 54 int mx=0; 55 //if (t>m) break; 56 //if (a[i]>50) break; 57 //cout<<i<<" "<<t<<endl; 58 memset(p,0,sizeof(p)); 59 for (j=1;j<=a[i];j++) 60 { 61 for (k=0;k<=t;k++) 62 { 63 ll x=0; 64 if (k+i*j>m) break; 65 p[k+i*j]+=now[k]*C[a[i]][j],mx=max(mx,k+i*j); 66 //if (k+i*j==6) cout<<i<<" "<<a[i]<<" "<<k<<" "<<now[k]<<" "<<C[a[i]][j]<<endl; 67 //cout<<k<<" "<<i<<" "<<j<<" "<<k+i*j<<" "<<now[k+i*j]<<endl; 68 } 69 } 70 t=mx; 71 for (j=0;j<=t;j++) 72 now[j]+=p[j]; 73 } 74 } 75 int tot=0; 76 for (i=1;i<=m;i++) 77 for (j=1;j<=a[i];j++) 78 as[++tot]=i; 79 for (i=1;i<tot;i++) 80 printf("%lld ",as[i]); 81 printf("%lld\n",as[tot]); 82 } 83 return 0; 84 }
Problem 1011
排序后从最后一个数开始扫
只要判断有多少对相邻的数的差<=k即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int inf=(1<<30)-1; 4 const int maxn=100010; 5 #define REP(i,n) for(int i=(0);i<(n);i++) 6 #define FOR(i,j,n) for(int i=(j);i<=(n);i++) 7 typedef long long ll; 8 int n,k; 9 int T; 10 int a[maxn]; 11 int main() 12 { 13 scanf("%d",&T); 14 while(T--) 15 { 16 scanf("%d%d",&n,&k); 17 for(int i=1;i<=n;i++) 18 scanf("%d",&a[i]); 19 sort(a+1,a+n+1); 20 int ans=1; 21 for(int i=n;i>=2;i--) 22 if(abs(a[i]-a[i-1])<=k) ans++; 23 else break; 24 printf("%d\n",ans); 25 } 26 return 0; 27 }