$$AVICII$$

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 */
View Code

 

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 }
View Code

 

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 }
View Code

 

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 } 
View Code

 

posted @ 2022-07-20 11:44  bootpuss  阅读(95)  评论(0编辑  收藏  举报