首页 > 其他分享 >Travelling Salesman and Special Numbers

Travelling Salesman and Special Numbers

时间:2023-10-07 23:46:43浏览次数:53  
标签:le 数字 变换 ll 这个 Numbers Travelling Salesman 我们

prologue

模拟赛的一道题,结果没做出来,丢大人,败大兴。所以过来糊一篇题解。

analysis

我们看到数据范围这么大,那么肯定不可以一个一个遍历(废话),所以就要考虑这个题目的性质。

我们先假设,极端数据 \(2 ^ {1000} - 1\),这个数字中包含了 \(999\) 个 1(正好感冒了能不能让我喝了)。下一次的数据就是 \(999\),这个时候,\(999\) 的二进制表示为 \(11 1110 0111\),下次就是 \(8\),再下次就是 \(1\) 了。这个时候的最少变换次数是 \(3\)。

我们看到这个数据缩小是很快的。那我们再进一步研究观察。

由于上限原因,所以我们第一次变换之后的数字一定为 \(\le 1000\) 的数字。我们又知道(不知道的掏计算器) \(2 ^ {10} = 1024\) 已经大于 1000 了,为了方便统计,适当放大数据。下次需要进行操作的数字就变成了 $ [0, 10] $ 就更小了,这个时候手搓一下,发现 \(7\) 这个数据是 \([0, 10]\) 之间的二进制表示下包含 1 最多的一个数字。

我们就求出来了这个恰好变换次数的上限。对于 100% 的数据而言,一定有:

  1. \(2 \le k \le 5\) 有解。
  2. \(k > 5\) 无解。

这个时候特判两个情况:

  1. \(k = 1\) 时,答案的个数为 \(length_s - 1\)。
  2. \(k = 0\) 时,答案为 1(只有 1 这种情况)。

我们之后就去考虑怎么计算这个值。

我们可以考虑一种类似于数位 dp 的思想,从高位往低位,用 \(f[i][j]\) 表示已经填了 i 个 1,剩下 j 位随便填,并且恰好 k 次变换之后能够变成 1 的方案数。

考虑递推式,从定义出发,预处理出来可能的值:

\[f[i][j] \gets f[i - 1][j] \]

\[f[i][j] \gets f[i][j] + f[i - 1][j + 1], (j \le n - 1) \]

计算方案数量:

\[res \gets (res + f[n - i - 1][t ++ ]) % P \]

注意,如果我们最后的这个数字符合我们的最后变换数量少一,就是最后可以变到 1,我们要给方案数加 1。

code time

#include <bits/stdc++.h>
using namespace std;
#define ll long long 
#define rl register ll 
#define endl '\n'

const ll N = 1010, P = 1e9 + 7;

char ch[N];

ll n, m, g[N], f[N][N];

int main()
{
    scanf("%s%lld", ch, &m);
    
    n = strlen(ch);
    
    if(m == 0) puts("1");
    else if(m == 1) cout << n - 1 << endl;
    else if(m > 5) cout << "0" << endl;
    else 
    {
        for(rl i=2; i <= 1000; ++ i)
        {
            ll cnt = 0;
            for(rl j=i; j; j >>= 1)
                if(j & 1) cnt ++; 
                
            g[i] = g[cnt] + 1;
        }
        
        for(rl i=1; i <= n; ++ i) f[0][i] = g[i] == m - 1;
        for(rl i=1; i <= n; ++ i)
            for(rl j=0; j <= n; ++ j)
            {
                f[i][j] = f[i - 1][j];
                if(j + 1 <= n) f[i][j] = (f[i][j] + f[i-1][j + 1]) % P;
            }
            
        ll res = 0, t = 0;
        for(rl i=0; i < n; ++ i)
            if(ch[i] == '1')
            {
                res = (res + f[n - i - 1][t]) % P; t ++ ;
            }
            
        if(g[t] == m - 1) cout << res + 1 << endl;
        else cout << res << endl;
    }
    return 0;
}

标签:le,数字,变换,ll,这个,Numbers,Travelling,Salesman,我们
From: https://www.cnblogs.com/carp-oier/p/17747674.html

相关文章

  • [LeetCode] 1352. Product of the Last K Numbers 最后 K 个数的乘积
    Designanalgorithmthatacceptsastreamofintegersandretrievestheproductofthelast k integersofthestream.Implementthe ProductOfNumbers class:ProductOfNumbers() Initializestheobjectwithanemptystream.voidadd(intnum) Appendsthei......
  • SQL Server: How to insert million numbers to table fast?
    YesterdayIattendedatlocalcommunityeveningwhereoneofthemostfamousEstonianMVPs–HennSarv–spokeaboutSQLServerqueriesandperformance.DuringthissessionwesawverycooldemosandinthispostingIwillintroduceyo......
  • 1521A - Nastia and Nearly Good Numbers
    A.NastiaandNearlyGoodNumbershttps://codeforces.com/problemset/problem/1521/A"""思路:1.就是普通的打印,NO的情况是只有b=1的时候才会出现,其他的都是YES,如果不想再继续分情况就把a*b放在中间做y,或者做x也可,避免(b-1)=1,最后要x+y=z"""forlinein[*open(0)......
  • CF1423K Lonely Numbers
    思路因为对于\(\gcd(a,b)\),\(\fraca{\gcd(a,b)}\),\(\fracb{\gcd(a,b)}\)中\(a\)和\(b\)是等价的,可以交换的。所以我们先令\(a>b\)。令\(\gcd(a,b)=d\),因为\(\fraca{\gcd(a,b)}\)有除法,所以我们应该想办法去除除法,就同乘以一个\(d\),即\(d^2\),\(a\),\(b\)三条边。......
  • P7 UVA11481 Arrange the Numbers
    UVA11481ArrangetheNumbers组合数问题。做法貌似很多,显然在前\(m\)个数中选\(k\)个,即\(C(m,k)\),然后后面有\(m-k\)个数需要保证不放在自己的位置上,所以后面整体是一个禁位问题,貌似可以用棋盘多项式去推禁位公式,但是暂时不会。不过还有另外一种思路,就是对于后面的\(n-......
  • Compatible Numbers
    CompatibleNumbers思路对于一个数\(x\),如果想要构造一个数\(y\)使得\(x\&y=0\)那么显然对于\(x\)的每一位:如果当前位是0,那么\(y\)这一位可以填\(1,0\)如果当前位是1,那么\(y\)这一位可以填\(0\)那么对于用这种方式构造出来的数的一些位是可以互换的,而互......
  • UVA10702 Travelling Salesman 题解
     UVA10702TravellingSalesman题解题面:有个旅行的商人,他每到一个的新城市,便卖掉所有东西再购买新东西,从而获得利润。从某城市A到某城市B有固定利润(B 到A 的利润可能不同)。已知城市可以重复到达,从S 点出发,经过T 个城市,有E个城市能作为终点,求最大的利润。先定义......
  • CF449D Jzzhu and Numbers
    有一个很蠢但是很好写的做法。就是你先令\(t_i\)为与起来恰好为\(i\)的方案数,然后\(g_i\)为与起来子集中有\(i\)的方案数。然后\(g_S=\sum\limits_{T\subseteqS}t_T\),反演一下变成\(t_{S}=\sum\limits_{T\subseteqS}(-1)^{|S|-|T|}g_{T}\)。注意到可以\(O(w)\)枚......
  • CF1808C Unlucky Numbers 题解
    可以证明答案是\(l\)或\(r\)的一段前缀,拼上后面全部相同的一段字符\(d\),证明方式类似数位dp。能够自由填的数字一定是相等的,这样不会影响幸运值。前面那些不能自由填写的,就是\(l\)或\(r\)的一段前缀。假如不是\(l\)或\(r\)的一段前缀,必然填写相等的更好,而这种情况已......
  • CF512D Fox And Travelling 题解--zhengjun
    计数好题。首先对于每个连通块独立考虑,最后合并答案。发现点数超过1的强连通分量一定删不掉。若连通块中存在点数超过1的强连通分量tarjan缩点之后,称这些点数超过1的强连通分量为关键点;那么两关键点之间的点也不能删;于是对于剩下的点直接dp即可,由于可删的子树......