• Codeforces 1142D Foreigner (DP)


    题意:首先定义了一种类数(标志数)

    1:1到9都是标志数。

    2:若x / 10是标志数,假设x /10在标志数中的排名是k, 若x的个位数小于k % 11, 那么x也是标志数。

    现在给你一个字符串,问有多少个子串代表的数字是标志数?

    思路:我们先假设已经求出的所有的标志数,并且知道每个标志数的rank(rank已经对11取模)。设dp[i][j]是第i个数字和第 i - 1位数字构成的2位数的rank为j,并且最高2位为这两位数字的合法数字的数目。可能有点拗口,我们举一个例子。

    假设字符串是321, 我们计算合法的子串有多少个。首先,dp[1][1]是1,所以1对答案的贡献是1。我们再看2对答案的贡献,合法的串有21, 2。2对答案的贡献是1,21是怎么来的呢?21的rank是1,所以dp[2][2] += dp[3][1],21来源于dp[3][1]。我们在看3对答案的贡献,3构成的合法的串是3, 32, 321。3对答案的贡献是1,那么32, 321是怎么来的呢?32的rank是6, 所以需要知道dp[2][6]是多少。2位置本身有个2,可以构成32,那么321怎么来的?321的rank是4,所以需要知道dp[3][4]是多少,dp[3][4]是1,所以返回1就行了。那么我们直接提前把答案的贡献累加上,当2前面的数与2构成的数rank是6的时候,可以知道此时前面的数与21构成的数(rank是4)也是对答案有贡献的,所以dp[2][6]是2。转移的时候可以暴力打表,打出每个2位数的rank,或者算出来就行了。

    具体做法看我队友的博客就行了。

    代码:

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int maxn = 100010;
    LL dp[maxn][11];
    LL ans = 0;
    char s[maxn];
    int main() {
    	scanf("%s",s + 1);
    	int n = strlen(s + 1);
    	for (int i = n; i >= 1; i--) {
    		for (int j = 0; j <= 10; j++) {
    			dp[i][j] = 1;
    			int t = s[i + 1] - '0';
    			if(i < n && j > t) {
    				dp[i][j] += dp[i + 1][(j * (j - 1) / 2 + t + 10) % 11];
    			}
    		}
    		if(s[i] != '0') ans += dp[i][s[i] - '0'];
    	}
    	printf("%lld
    ", ans);
    } 
    

      

  • 相关阅读:
    [HAOI2010]软件安装
    「HNOI2015」菜肴制作
    [ZJOI2007] 小Q的矩阵游戏 (模板—Dinic)
    「POI2012」约会 Rendezvous
    [APIO2016]划艇
    [CQOI2011]放棋子
    【SDOI2015】bzoj3990 排序
    [bzoj2242] [SDOI2011]计算器
    模板—BSGS
    【BZOJ1227】[SDOI2009]虔诚的墓主人
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10666192.html
Copyright © 2020-2023  润新知