• 2022/8/8 比赛思维+状压dp


    活动地址:CSDN21天学习挑战赛

    C-Constructive Problems Never Die_"蔚来杯"2022牛客暑期多校训练营7 (nowcoder.com)

      可以想一下,每个数的坐标是唯一的并且是一个排列,那我们就可以根据坐标来构造排列,用b[i]维护坐标,遍历a数组,如果发现坐标和值相等了,那就去找第一个和下标不等的数,然后交换两者的坐标,可以发现交换后的两个数是一定符合条件的,所以遍历完之后输出b数组就可以了,NO的情况就是整个数组都为1个值的时候,c数组维护的是a数组排序去重后的值,d数组维护的是每个数的下标,其实这个数组有点牵强,因为a中会有重复的,所以d数组维护的是最后出现a[i]最后一次出现时的下标,但这样也够了,达到了找数的目的

    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define lowbit(i) ((i)&(-i))
    5. const ll mod=998244353;
    6. const int N = 2e5+5;
    7. ll t,n,a[100005],b[100005],c[100005],d[100005];
    8. int main(){
    9. scanf("%lld",&t);
    10. while(t--){
    11. scanf("%lld",&n);
    12. for(int i=1;i<=n;i++) a[i]=b[i]=c[i]=d[i]=0;
    13. for(int i=1;i<=n;i++) scanf("%lld",&a[i]),b[i]=i,c[i]=a[i],d[a[i]]=i;
    14. sort(c+1,c+n+1);
    15. ll m=unique(c+1,c+n+1)-c-1,flag=1;
    16. for(int i=1;i<=n;i++){
    17. if(a[i]==b[i]){
    18. ll ma=1;
    19. while(a[i]==c[ma]&&ma<=m) ma++;
    20. if(ma>m){flag=0;break;}
    21. //cout<
    22. swap(b[i],b[d[c[ma]]]);
    23. }
    24. }
    25. if(flag) printf("YES\n");
    26. else {printf("NO\n");continue;}
    27. for(int i=1;i<=n;i++) printf("%lld ",b[i]);
    28. printf("\n");
    29. }
    30. system("pause");
    31. return 0;
    32. }

    F-Candies_"蔚来杯"2022牛客暑期多校训练营7 (nowcoder.com)

    可以发现两种操作互不影响,即只要发现可以操作尽管操作就行,所以这题需要在意的就只是删除两个数的操作了,这个操作vector就可以优雅的完成,为了思路更加简洁,从0到n-2扫一遍之后,如果还剩下2个或多个数,那么就在看看1和最后一个可不可以,可以就继续看2和倒数第二个可不可以,直到不符合条件

    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define lowbit(i) ((i)&(-i))
    5. const ll mod=998244353;
    6. const int N = 2e5+5;
    7. ll n,x;
    8. vectorv;
    9. int main(){
    10. scanf("%lld%lld",&n,&x);
    11. for(int i=1;i<=n;i++){
    12. ll y;scanf("%lld",&y);
    13. v.push_back(y);
    14. }
    15. ll y=0,ans=0;
    16. while(ysize()-1&&v.size()>0){
    17. //cout<
    18. if(v[y]==v[y+1]||v[y]+v[y+1]==x){
    19. ans++;
    20. v.erase(v.begin()+y);
    21. v.erase(v.begin()+y);
    22. y=max(0LL,y-1);
    23. }
    24. else y++;
    25. //cout<
    26. }
    27. if(v.size()>1){
    28. ll l=0,r=v.size()-1;
    29. while(l
    30. if(v[l]==v[r]||v[l]+v[r]==x){ans++;l++,r--;}
    31. else break;
    32. }
    33. }
    34. printf("%lld\n",ans);
    35. system("pause");
    36. return 0;
    37. }

    G-Regular Expression_"蔚来杯"2022牛客暑期多校训练营7 (nowcoder.com)

    读懂题意之后根据1个字母,2个字母相等或不等,3个或多个字母全相等或不等 分类讨论就行

    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define lowbit(i) ((i)&(-i))
    5. const ll mod=998244353;
    6. const int N = 2e5+5;
    7. ll q;
    8. char s[200005];
    9. int main(){
    10. scanf("%lld",&q);
    11. while(q--){
    12. scanf("%s",s+1);
    13. ll n=strlen(s+1),flag=1;
    14. for(int i=2;i<=n;i++)
    15. if(s[i]!=s[i-1]){flag=0;break;}
    16. if(n==1) printf("1 2\n");
    17. else if(n==2){
    18. if(flag) printf("2 8\n");
    19. else printf("2 6\n");
    20. }
    21. else{
    22. if(flag) printf("2 4\n");
    23. else printf("2 2\n");
    24. }
    25. }
    26. system("pause");
    27. return 0;
    28. }

    356A - Knight Tournament 并查集辅助跳跃区间

    这题关键点就是如何跳过那些已经被访问过的骑士,令s[i]为从i开始第一个没被访问的骑士,一开始s[i]=i,当i被访问后,s[i]也就变成i+1了,我们访问的时候就findd(i+1)这样跳;一开始试的用数组跳但还是太暴力了,用vector二分也还是很暴力,最后看题解发现并查集也可以

    CF356A - little_carl 的博客 - 洛谷博客

    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define lowbit(i) ((i)&(-i))
    5. const ll mod=998244353;
    6. const int N = 2e5+5;
    7. ll n,m,ans[300005],s[300005];
    8. ll findd(ll x){return x==s[x]?x:s[x]=findd(s[x]);}
    9. int main(){
    10. scanf("%lld%lld",&n,&m);
    11. for(int i=1;i<=n+1;i++) s[i]=i;
    12. for(int i=1;i<=m;i++){
    13. ll l,r,x;
    14. scanf("%lld%lld%lld",&l,&r,&x);
    15. for(int j=findd(l);j<=r;j=findd(j+1)){
    16. if(j!=x){
    17. ans[j]=x;
    18. s[j]=j+1;
    19. }
    20. }
    21. }
    22. for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
    23. system("pause");
    24. return 0;
    25. }

    P7859 [COCI2015-2016#2] GEPPETTO - 洛谷 | 位运算

    把用材料和不用看成1和0,然后枚举n的二进制就可以了,这题其实不是状压dp,只是用到了状压dp中的位运算的操作罢了

    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define lowbit(i) ((i)&(-i))
    5. const ll mod=998244353;
    6. const int N = 2e5+5;
    7. ll n,m,x[405],y[405],a[25];
    8. int main(){
    9. scanf("%lld%lld",&n,&m);
    10. for(int i=1;i<=m;i++) scanf("%lld%lld",&x[i],&y[i]);
    11. ll ans=0;
    12. for(int s=0;s<(1<
    13. for(int i=1;i<=n;i++)
    14. if(s>>(i-1)&1) a[i]=1;
    15. else a[i]=0;
    16. ll flag=1;
    17. for(int i=1;i<=m;i++){
    18. if(a[x[i]]&&a[y[i]]){flag=0;break;}
    19. }
    20. if(flag) ans++;
    21. }
    22. printf("%lld\n",ans);
    23. system("pause");
    24. return 0;
    25. }

    P1278 单词游戏 - 洛谷 | 状压dp

    这也算是排列问题的一种,所以做法也类似,但是需要注意的是答案不再是从全被选上的排列中找了,因为全部用上不一定是最优的,所以要及时更新最大值,另外字符串之间要首尾相接只需要判断一下就可以了,作为蓝题还是不算难的,毕竟可以自己做出来,,,

    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define lowbit(i) ((i)&(-i))
    5. const ll mod=998244353;
    6. const int N = 2e5+5;
    7. ll n,dp[100006][20];
    8. char ch[20][110];
    9. int main(){
    10. scanf("%lld",&n);
    11. ll ans=0;
    12. for(int i=1;i<=n;i++) scanf("%s",ch[i]+1);
    13. for(int i=1;i<=n;i++) dp[1<-1][i]=strlen(ch[i]+1);
    14. for(int s=0;s<(1<
    15. for(int i=1;i<=n;i++)
    16. for(int j=1;j<=n;j++){
    17. if(s>>(j-1)&1) continue;
    18. if(ch[i][strlen(ch[i]+1)]!=ch[j][1]||i==j) continue;
    19. dp[s|(1<-1)][j]=max(dp[s|(1<-1)][j],dp[s][i]+(ll)strlen(ch[j]+1));
    20. ans=max(ans,dp[s|(1<-1)][j]);
    21. //cout<
    22. }
    23. printf("%lld\n",ans);
    24. system("pause");
    25. return 0;
    26. }

    P2051 [AHOI2009] 中国象棋 - 洛谷 | 状态dp

    感觉这题像是排兵布阵的强化版,但是排兵布阵我也忘了咋写了,应该先写排兵布阵的,,,

    这个博客讲的很清楚,将dp的情况分的很清楚,f[i][j][k]表示已经放了i行,有j列放了一个棋子,有k列放了2个棋子,分别讨论第i行放一个棋子,放两个棋子和不放棋子的情况

    题解 P2051 【[AHOI2009]中国象棋】 - 顾z 的博客 - 洛谷博客

    1. #include
    2. using namespace std;
    3. #define ll long long
    4. #define lowbit(i) ((i)&(-i))
    5. const ll mod=9999973;
    6. const int N = 2e5+5;
    7. ll n,m,ans;
    8. ll f[105][105][105];
    9. ll C(ll x){
    10. return x*(x-1LL)/2%mod;
    11. }
    12. int main(){
    13. scanf("%lld%lld",&n,&m);
    14. f[0][0][0]=1;
    15. for(int i=1;i<=n;i++)
    16. for(int j=0;j<=m;j++)
    17. for(int k=0;k<=m-j;k++){
    18. //不放棋子
    19. f[i][j][k]=f[i-1][j][k];
    20. //放一个棋子
    21. //放在一个有棋子的列
    22. if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1)%mod)%mod;
    23. //放在没有棋子的列
    24. if(j>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-(j-1)-k)%mod)%mod;
    25. //放两个棋子
    26. //放在一个有棋子的列和一个没有棋子的列
    27. if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*j*(m-j-(k-1))%mod)%mod;
    28. //放在没有棋子的列
    29. if(j>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*C(m-(j-2)-k)%mod)%mod;
    30. if(k>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*C(j+2)%mod)%mod;
    31. }
    32. for(int i=0;i<=m;i++)
    33. for(int j=0;j<=m;j++)
    34. ans=(ans+f[n][i][j])%mod;
    35. printf("%lld\n", ans);
    36. system("pause");
    37. return 0;
    38. }

  • 相关阅读:
    【爬虫】7.4. 字体反爬案例分析与爬取实战
    如何在外网访问公司项目?快解析实现内网ip让公网连接
    怎么把自己写的组件发布到npm官方仓库??
    D1. 388535 (Easy Version)(异或+二进制位)
    java基础10题
    Sychronized的偏向锁、轻量级锁、重量级锁
    Jmeter进阶-接口自动化
    小程序进阶-env(safe-area-inset-bottom)的使用
    扩散模型学习
    swoole进行性能查看火焰图tideways_xhprof xhgui
  • 原文地址:https://blog.csdn.net/weixin_52621204/article/details/126238452