HDU 4665 Mutiples on a circle (圆环DP)
题意
N个数的圆环上有多少种方案可以使得选出来的一段数是K的倍数(N<=50000, K<=200, a[i]<=1000).
思路
多校第七场1004。圆上的DP……大脑太简单处理一些细节时总是短路= =……
我处理圆的方法是把圆环展开成2*N个数。我们设以第i个数结尾的所有段,按照 mod k 的余数分类的方案数为hash[i][r],r 表示余数。那么如果我们在段末尾加上i+1,我们就可以仅根据余数来确定这些段在添加了第i+1个数之后mod K的余数是(r*exp(10,digits[i+1]) + number[i+1])%k。(一开始样例只有1位数我就直接把digits当1了我是有多逗……)。
注意的是我们需要排除段长度大于N的情况,所以当我们处理到i+N时,需要减去从i到i+N-1的情况,这个可以事先计算出来用dp[i]表示。还要注意一点是要注意我们在处理区间[N+1,2*N]时相当于又把[1,N]中的情况算了一遍,所以最后要减去。(跨区间的计算,即首尾连接的计算没有多余,不用减)。
然后交上去超时了擦。。。目测是卡了常数。。。标程处理圆环的方法是先把以首数字为结尾的情况算出来,然后直接在[1,N]上处理即可,这样不会有重复的计算。于是只好各种优化……精简的精简、再把(r*exp(10,digits[i+1]) + number[i+1])%k这个预处理用数组存了一下,然后终于过了。。。
代码
【我的代码】
[cpp]
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i, begin, end)   for (int i = begin; i <= end; i ++)
using namespace std;
typedef long long LL;
typedef vector <int> VI;
typedef set <int> SETI;
typedef queue <int> QI;
typedef stack <int> SI;
int dp[50005];
int a[50005];
int bit[50005];
int e[200005];
int hash[205], tmp[250];
int mulmod[205][5][205];
inline int get_bit(int x){
    int num = 0;
    while(x){
        num ++;
        x /= 10;
    }
    return num;
}
inline void init(int n, int k, int length){
    e[0] = 1%k;
    REP(i, 1, length){
        e[i] = e[i-1]*10 % k;
    }
    REP(i, 0, k){
        REP(j, 1, 4){
            REP(m, 0, k){
                mulmod[i][j][m] = (i*e[j]+m)%k;
            }
        }
    }
    dp[1] = 0;  int len = -bit[1];
    REP(i, 1, n){
        len += bit[i];
        dp[1] = ( dp[1]*e[bit[i]] + a[i] ) % k;
    }
    REP(i, 2, n){
        dp[i] = ( ( ( dp[i-1] - a[i-1]*e[len] )*e[bit[i-1]] + a[i-1]) % k + k ) % k;
        len = len + bit[i-1] - bit[i];
    }
}
int main(){
	int n, k;
	while(scanf("%d %d", &n, &k) != EOF){
        int length = 0;
        REP(i, 1, n){
            scanf("%d", &a[i]);
            bit[i] = get_bit(a[i]);
            length += bit[i];
            a[i] = a[i] % k;
        }
        init(n, k, length);
        //main
        MEM(hash, 0);
        int res = 0, rn = 0;
        REP(i, 1, n){
            res += hash[0];
            MEM(tmp, 0);
            tmp[a[i]] ++;
            for (int j = 0; j < k; j ++){
                if (hash[j] > 0)    tmp[mulmod[j][bit[i]][a[i]]] += hash[j];
            }
            for (int j = 0; j < k; j ++){
                hash[j] = tmp[j];
            }
        }
        res += hash[0];
        rn = res;
        REP(i, n+1, 2*n){
            res += hash[0];
            if (i == n + 1) rn = res;
            hash[dp[i-n]] --;
            MEM(tmp, 0);
            tmp[a[i-n]] ++;
            for (int j = 0; j < k; j ++){
                if (hash[j] > 0)    tmp[mulmod[j][bit[i-n]][a[i-n]]] += hash[j];
            }
            for (int j = 0; j < k; j ++){
                hash[j] = tmp[j];
            }
        }
        res += hash[0];
        printf("%d\n", res-rn);
	}
	return 0;
}
[/cpp]
【标程】
[cpp]
#include <cstdio>
#include <cstring>
//Assume n<=3*10^4, mod<=10^3
const int maxn = 50005, maxmod=205;
int n, mod, number[maxn], digits[maxn], e[maxn * 3];
int count[maxn][maxmod];
inline int count_digits(int number) {
	if (!number) return 1;
	int ret = 0;
	while (number) ret++, number /= 10;
	return ret;
}
int main() {
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt","w",stdout);
	e[0] = 1;
	while (scanf("%d%d", &n, &mod) != EOF) {
		memset(count,0,sizeof(int) * maxmod * n);
for (int i = 1; i < n * 3; i++)
			e[i] = e[i - 1] * 10 % mod;
for (int i = 0; i < n; i++) {
			scanf("%d", number + i);
			digits[i] = count_digits(number[i]);
		}
		number[n] = number[0];
		digits[n] = digits[0];
int s = 0, length = 0, answer = 0;
		for (int i = n; i; i--) {
			s = (s + number[i] * e[length]) % mod;
			length += digits[i];
			count[0][s]++;
		}
		answer += count[0][0];
for (int i = 1; i < n; i++) {
			for (int r = 0; r < mod; r++)
				count[i][(r * e[digits[i]] + number[i]) % mod] += count[i - 1][r];
			s = (s * e[digits[i]] + number[i]) % mod;
			count[i][s]--;
			count[i][number[i] % mod]++;
			s = ((s - number[i] * e[length]) % mod + mod) % mod;
			answer += count[i][0];
		}
printf("%d\n", answer);
	}
}
[/cpp]
HDU 4665 Mutiples on a circle (圆环DP)的更多相关文章
- HDU 4669 Mutiples on a circle 数位DP
		
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4669 考察对取模的的理解深不深刻啊,当然还有状态的设计····设d[i][j]表示以第i个数结尾,余 ...
 - HDU 4669 Mutiples on a circle(环状DP)
		
题目链接 这是最早看懂题意的一题,状态转移,挺好想..但是比赛时候,就是没有想到怎么去重,而且当时有些情况,也没注意到. 先预处理的dp[0]的情况,就是以p[0]为结尾的情况.之后D就行了,例如样例 ...
 - HDU 4669 Mutiples on a circle (DP , 统计)
		
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 题意:给出一个环,每个点是一个数字,取一个子串,使 ...
 - HDU 4669 Mutiples on a circle (2013多校7 1004题)
		
Mutiples on a circle Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Oth ...
 - HDU-4669 Mutiples on a circle 环形DP
		
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4669 题意:给一串数字连乘一个环,求连续的子串中组成的新的数字能被K整除的个数. 首先容易想到用DP来 ...
 - HDU 4669 Mutiples on a circle 不知道该归为哪一类。
		
题意:给你N个珠宝和一个K,每个珠宝上面都有数字,这个珠宝做成项链,把珠宝上的数字拼起来如果可以整除掉K,那么久说这个数字为wonderful value,问你有多少种方案可以组成WONDERFUL ...
 - HDU 4669 Mutiples on a circle 动态规划
		
参考了官方题解给的方法: 对于处理循环,官方给了一种很巧妙的方法: #include <cstdio> #include <cstring> #include <cstd ...
 - hdu 5025 Saving Tang Monk 状态压缩dp+广搜
		
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4092939.html 题目链接:hdu 5025 Saving Tang Monk 状态压缩 ...
 - HDU 3016 Man Down (线段树+dp)
		
HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
 
随机推荐
- 【U3D】脚本引用的类,如何显示在编辑器界面
			
有时候,我们的类里面会组合其他功能模块 如何让这些功能类的值在编辑器界面出现呢? 1:引用类的访问类型必须是Public 2: 类必须声明为可序列化的,即在类头加入以下声明 [System.Seria ...
 - eclipse中添加tomcat ServerName 无法输入
			
Eclipse的开发过程中,无法从以下方式,添加Tomcat服务器. 其中ServerName是被置为灰色的,无法编辑. 如何解决 1. 关闭Eclipse 2. 打开WorkSpace所在的 ...
 - c++之旅:继承
			
继承 继承有关于权限的继承,多继承和虚继承 权限继承 权限继承有公有继承,保护继承和私有继承 公有继承 公有继承可以继承父类的public和protected属性和方法 #include <io ...
 - 简单地理解HTTPS 转
			
原文地址:http://www.nowamagic.net/librarys/veda/detail/2394 我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取.所以很多银行网站或电子邮箱等 ...
 - java多态 以及静态绑定  动态绑定积累
			
重载,英文名是overload,是指在一个类中定义了一个以上具有相同名称的方法,这些方法的参数个数.参数类型和顺序不能相同.返回类型可以相同,也可以不同. 重写,英文名是overrid,是指在继承情况 ...
 - Django学习笔记之uWSGI详解
			
WSGI是什么? WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义 ...
 - MVC 中 注册不成功 或其他操作不成功 提示办法
			
在Controller中 .cs public ActionResult AddUser(User u) { …… try { …… GetInsertUser(u); // 注册 ...
 - 20145312 实验三《敏捷开发与XP实践》
			
20145312 实验三<敏捷开发与XP实践> 实验内容 使用 git 上传代码 使用 git 相互更改代码 与20145318同学一组,使用git相互更改代码 同组实验报告链接:http ...
 - 解读:Hadoop序列化类
			
序列化(serialization)是指将结构化的对象转化字节流,以便在进程间通信或写入硬盘永久存储. 反序列化(deserialization)是指将字节流转回到结构化对象的过程. 需要注意的是,能 ...
 - 【前端】javaScript 常用技巧总结
			
javaScript 常用技巧总结 1. 彻底屏蔽鼠标右键 oncontextmenu="window.event.returnValue=false" <table b ...