2022HDU多校(一)
A
这题一开始打算hash二分加数据结构,发现k的条件处理不了
然后开始在trie树上dp,也伪了
正解中exkmp和hash二分效果一样,关键是模意义下差分
1 #include <bits/stdc++.h>
2 using namespace std;
3 #define ull unsigned long long
4 const int mod=998244353;
5 const ull mo=131;
6 const int MAXN=1e6+17;
7 string S;
8 int k,n;
9 ull qsm[MAXN],bin[MAXN];
10 inline ull Get(int l,int r){
11 if(r<l)return 0;
12 return qsm[r]-qsm[l-1]*bin[r-l+1];
13 }
14 int sm[MAXN];
15 int main(){
16 bin[0]=1;
17 for(int i=1;i<=1e6;++i)bin[i]=bin[i-1]*mo;
18 int T;scanf("%d",&T);
19 while(T--){
20 cin>>S;
21 scanf("%d",&k);
22 n=S.length();
23 for(int i=0;i<=n+1;++i)qsm[i]=sm[i]=0;
24 for(int i=1;i<=n;++i)qsm[i]=qsm[i-1]*mo+(S[i-1]-'a'+1);
25 for(int i=1;i<=n;++i){
26 int l=0,r=n-i+1;
27 while(r-l>1){
28 int mid=l+r>>1;
29 if(Get(1,1+mid-1)==Get(i,i+mid-1))l=mid;
30 else r=mid;
31 }
32 int x;
33 if(Get(1,1+r-1)==Get(i,i+r-1))x=r;
34 else x=l;
35 cout<<x<<" ";
36 if(x<k)continue;
37 if(i-1+k<=n)sm[i-1+k]++;
38 if(i-1+k*(x/k+1))sm[i-1+k*(x/k+1)]--;
39 }
40 cout<<endl;
41 int ans=1;
42 for(int i=1;i<=n;++i){
43 if(i+k<=n)sm[i+k]=(sm[i+k]+sm[i])%mod;
44 ans=1LL*ans*(sm[i]+1)%mod;
45 }
46 printf("%d\n",ans);
47 }
48 return 0;
49 }
50 /*
51
52 1
53 abababac
54 2
55
56 */
B
暴搜
C
dp[i][j][k]表示枚举到i个物品,异或和为j,容量为k的合法性
实际上dp是n*1024*m的,用biset优化,将容量k压成一个bitset数
然后加上v[i]实际操作为bitset数左移v[i]位
优化的本质是利用bitset的位运算缩小了容量k的枚举
1 #include <bits/stdc++.h>
2 using namespace std;
3 int n,m;
4 bitset<1024>dp[1024],tmp[1024];
5 int v[1025],w[1025];
6 int main(){
7 int T;scanf("%d",&T);
8 while(T--){
9 scanf("%d%d",&n,&m);
10 for(int i=1;i<=n;++i)scanf("%d%d",&v[i],&w[i]);
11 for(int i=0;i<1024;++i)dp[i].reset(),tmp[i].reset();
12 dp[0][0]=1;
13 for(int i=1;i<=n;++i){
14 for(int j=0;j<1024;++j)tmp[j]=dp[j]<<v[i];
15 for(int j=0;j<1024;++j)dp[j]|=tmp[j^w[i]];
16 }
17 int ans=-1;
18 for(int j=0;j<1024;++j)if(dp[j][m])ans=j;
19 cout<<ans<<endl;
20 }
21 return 0;
22 }
D
出题人好喜欢bitset,
先筛素数,枚举三个点复杂度会爆掉
考虑枚举两个点,第三个点用bitset压位,取&操作使第三条边的枚举不重复
K
签到题
I
将第一个点作为水平方向的点,然后枚举每个点,如果枚举的点和第一个点不在同一横向直线上,则可以得到三个点作为中心尝试判断
除此之外再进行三次坐标变换即可(竖直方向,切比雪夫坐标变换旋转45度)
1 #include<bits/stdc++.h>
2 const int MAXN=1e6+17;
3 using namespace std;
4 #define ll long long
5 int x[MAXN],y[MAXN],n;
6 int a[MAXN],b[MAXN];
7 inline bool pd(int x,int y){
8 return (x==0||y==0||x==y||x+y==0);
9 }
10 inline bool check(int _x,int _y){
11 for(int i=1;i<=n;++i)
12 if(!pd(_x-x[i],_y-y[i]))return false;
13 return true;
14 }
15 inline bool work(){
16 int ok=true;
17 for(int i=2;i<=n;++i){
18 if(x[i]==x[1])continue;
19 ok=false;
20 if(check(x[1],y[i]))return true;
21 if(check(x[1],y[i]+(x[i]-x[1])))return true;
22 if(check(x[1],y[i]-(x[i]-x[1])))return true;
23 break;
24 }
25 if(ok)return true;
26 return false;
27 }
28 inline bool solve(){
29 scanf("%d",&n);
30 for(int i=1;i<=n;++i)scanf("%d%d",&a[i],&b[i]);
31
32 for(int i=1;i<=n;++i)x[i]=a[i],y[i]=b[i];
33 if(work())return true;
34
35 for(int i=1;i<=n;++i)x[i]=b[i],y[i]=a[i];
36 if(work())return true;
37
38 for(int i=1;i<=n;++i)x[i]=a[i]+b[i],y[i]=a[i]-b[i];
39 if(work())return true;
40
41 for(int i=1;i<=n;++i)x[i]=a[i]-b[i],y[i]=a[i]+b[i];
42 if(work())return true;
43
44 return false;
45 }
46 int main(){
47 int T;
48 scanf("%d",&T);
49 while(T--)puts(solve()?"YES":"NO");
50 return 0;
51 }
L
结论题,写挂了
实际上A的最优策律是把每一种数字平分,而B选择哪个集合最终结果都是一样的
1 #include<bits/stdc++.h>
2 using namespace std;
3 int n;
4 int a[1100000];
5 int main(){
6 cin>>n;
7 for(int i=0;i<=n;++i)cin>>a[i];
8 for(int i=n;i>0;--i)a[i-1]+=a[i]/2;
9 if(a[0]) cout<<"Alice\n";
10 else cout<<"Bob\n";
11 return 0;
12 }