• hgoi#20190706


    更好的阅读体验

    我的博客观看

    T1-质因数

    有一个正整数数列a1,a2…an。定义函数f(x)为x 的不同的质因数数量。
    求f(a1),f(a2)…f(an)。

    解法

    写个欧拉筛,然后欧拉筛的时候直接判断一下有没有新增质因数

    ac代码

    #include<bits/stdc++.h>
    using namespace std;
    int n,cnt,x,a[1000010],p[1000010],dp[1000010];
    void oula()
    {
    	for(int i=2;i<=1000000;i++)
    	{
    		if(a[i]==0)a[i]=p[++cnt]=i,dp[i]=1;
    		for(int j=1;j<=cnt;j++)
    		{
    			if(i*p[j]>1000000||a[i]<p[j])break;
    			a[i*p[j]]=p[j];
    			if(i%p[j]==0)dp[i*p[j]]=dp[i];
    			else dp[i*p[j]]=dp[i]+1;
    		}
    	}
    }
    int main()
    {
    	freopen("easy.in","r",stdin),freopen("easy.out","w",stdout),oula(),scanf("%d",&n);
    	while(n--)scanf("%d",&x),printf("%d
    ",dp[x]);
    	return 0;
    } 
    

    T2-编码

    一个字符串str的p型编码a的定义如下:把str表示成b1个c1,b2个c2...bn个cn,然后将b1,c1,b2,c2,...,bn,cn首尾拼接成的字符串中最短的字符串设为a。例如:字符串122344111可被描述为"1个1、2个2、1个3、2个4、3个1",因此我们说122344111的p型编码为1122132431。
    类似的道理,00000000000可描述为"11个0",因此它的p型编码为110;100200300可描述为"1个1、2个0、1个2、2个0、1个3、2个0",因此它的p型编码为112012201320。
    很显然,一个串str的p型编码是固定的,但是可能有多个串的p型编码相同。现在已知一个字符串str的p型编码a,但不知道原来的字符串,求有多少种字符串的p型编码为a。

    解法

    显然是个dp的题目,我们设状态dp[i]为以第i个字符为结尾的b[x]的方案数,那么最终的答案就是dp[n-1]
    我们想状态转移,dp[i]可以从dp[j] (1<=j<=i-2)推的,顺便一提,初值都是1
    问题是无法转移的情况,一种是a[i]为0时,不能从dp[i-2]转移至dp[i]
    因为dp[i-2]的时候一个b[x]结尾了,a[i-1]是c[x],b[i+1]就是a[i]
    而题目要求的是最短字符串,所以不会有前导0,所以这种情况不行
    另一种情况,如果a[j+1]==a[i+1],就一定能合并,而不是最短的,所以也不能转移
    我们只需要维护一个sum以及各种c[x]的方案数即可

    ac代码

    #include<bits/stdc++.h>
    #define mod 998244353
    using namespace std;
    char s[1000010];
    int n,sum,ss[10],a[1000010],dp[1000010];
    int main()
    {
    	freopen("hard.in","r",stdin),freopen("hard.out","w",stdout),scanf("%s",s),n=strlen(s);
    	for(int i=1;i<=n;i++)a[i]=s[i-1]-'0',dp[i]=1;
    	for(int i=3;i<n;i++)
    	{
    		if(a[i]!=0)sum=(sum+dp[i-2])%mod,ss[a[i-1]]=(ss[a[i-1]]+dp[i-2])%mod;
    		dp[i]=((dp[i]+sum-ss[a[i+1]])%mod+mod)%mod;
    	}
    	if(a[1]==0)puts("0");else printf("%d
    ",dp[n-1]);
    	return 0;
    }
    

    T3-八卦阵

    有一个八卦阵。这个阵可以认为是一个n个点,m条边的有向图。每条边i有一个困难a[i]。每个点u有八个状态:b[u][1],b[u][2],...,b[u][8],这八个状态均为[1,8]之间的整数(不一定是排列),在第i 秒中,u的状态为b[u][(i-1)%8+1]。对于任意两个状态i,j都存在一个复杂度c[i][j]。
    现在想从1号点走到n号点,在第一秒开始时在1号点,每次可以用1秒从当前点u走到另一个有边相连的点v。也就是说,在第一秒内走过第一条边,在第二秒内走过第二条边……由于八卦阵极其巧妙,必须砸出一些榔头才能走过一条边。若在第i秒通过第j条边从点u走到点v,需要砸出a[j]+c[b[u][(i-1)%8+1]][b[v][(i-1)%8+1]]个榔头。
    请计算出至少要多少个榔头才能从点1走到点n。

    解法

    这道题挺水的,感觉还没T2难,只要跑最短路就好了,把一个点剖成八个点,然后跑最短路
    考虑到会被卡spfa,优先队列优化一下,不多说咯QWQ

    ac代码

    #include<bits/stdc++.h>
    #define inf (2e9)
    #define v e[i].to
    #define d e[i].w+c[b[u.nw][u.t]][b[v][u.t]]
    using namespace std;
    struct node{int to,w,next;}e[300010];
    int n,m,cnt,x,y,z,head[100010],c[10][10],b[100010][10],dis[100010][10],used[100010][10];
    struct Node{int nw,t,dd;bool operator<(const Node b)const{return dd>b.dd;}}u;
    priority_queue<Node>q;
    void add(){e[++cnt]={y,z,head[x]},head[x]=cnt;}
    void spfa()
    {
    	while(!q.empty())
    	{
    		while(used[q.top().nw][q.top().t])q.pop();
    		u=q.top(),q.pop(),used[u.nw][u.t]=1;
    		if(u.nw==n)printf("%d
    ",dis[u.nw][u.t]),exit(0);
    		for(int i=head[u.nw];i;i=e[i].next)
    			if(!used[v][u.t%8+1])if(u.dd+d<dis[v][u.t%8+1])
    				dis[v][u.t%8+1]=u.dd+d,q.push({v,u.t%8+1,dis[v][u.t%8+1]});
    	}
    }
    int main()
    {
    	freopen("hammer.in","r",stdin),freopen("hammer.out","w",stdout),scanf("%d%d",&n,&m);
    	for(int i=1;i<=8;i++)for(int j=1;j<=8;j++)scanf("%d",&c[i][j]);
    	for(int i=1;i<=n;i++)for(int j=1;j<=8;j++)scanf("%d",&b[i][j]),dis[i][j]=inf;
    	for(int i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&z),add();
    	dis[1][1]=0,q.push({1,1,0}),spfa();
    	return 0;
    }
    
  • 相关阅读:
    [APIO2014]序列分割
    [HNOI2008]玩具装箱TOY
    [ZJOI2007]时态同步
    [FJOI2014]最短路径树问题
    [IOI2011]Race
    [国家集训队]聪聪可可
    矩阵加速递推
    Codeforces Round #669 题意及思路
    Codeforces Round #670 题意及思路
    Codeforces Round #671 题意及思路
  • 原文地址:https://www.cnblogs.com/muronglin/p/hgoi-20190706.html
Copyright © 2020-2023  润新知