0%

很容易想到类似素数筛选的方法,但是发现空间这个题目开的很小,所以开那么大空间不行

发现d(n) - n < 7 * 9,函数与自身相减是小于63,某个数,最多只会影响它的第63个后面的数,考虑用一个类似滚动数组的hash,如果这个数是,那么就存储,如果这个数不是。就不做

不管怎样都要把后面一个消除影响以及这个数还原为可以的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/* From: Lich_Amnesia
* Time: 2013-12-20 22:34:03
*
* SGU 108
* */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
using namespace std;

const int INF = ~0u>>1;
typedef pair <int,int> P;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
#define maxn 5010

struct node{
int id,ans,val;
}num[maxn];

bool cmp(node a,node b){
return a.val < b.val;
}

int val[10010];
bool vis[66];
int ans[maxn];
int main(){
int n,k;
scanf("%d%d", &n, &k);
for (int i = 0; i < k; i++){
scanf("%d", &num[i].val);
num[i].id = i;
}
int len = 0;
int now = 0;
sort(num,num + k,cmp);

//求d(n)的数字部分的和
for (int i = 1; i <= 10000; i ++){
val[i] = val[i /10] + i % 10;
}
memset(vis,1,sizeof(vis));

for (int i = 1; i <= n; i ++){
if (vis[i % 63]){
len ++;
while (num[now].val == len){
ans[num[now++].id] = i;
}
}

vis[i % 63] = 1;

int next = i + val[i / 10000] + val[i % 10000];
vis[next % 63] = 0;

}
cout << len << endl;
for (int i = 0; i < now; i++){
if (i) printf(" ");
printf("%d", ans[i]);
}
cout << endl;
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* From: Lich_Amnesia
* Time: 2013-12-16 20:21:11
*
* POJ 3420 DP + 状态压缩 + 矩阵快速幂
* */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
using namespace std;

const int INF = ~0u>>1;
typedef pair <int,int> P;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
typedef long long ll;
#define maxn 100010
ll ans[16][16];
#define N 16
void product_mod(ll a[][16], ll b[][16],int n, ll mod){
ll c[N][N] = {};
for (int i = 0; i < n; i ++){
for (int j = 0; j < n; j ++){
for (int k = 0; k < n; k ++){
c[i][j] += a[i][k] * b[k][j];
}
c[i][j] %= mod;
}
}
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
a[i][j] = c[i][j];
}
}
}

void power_mod(ll a[][N], ll x, int n, ll mod){
memset(ans, 0, sizeof(ans));
for (int i = 0; i < n; i ++) ans[i][i] = 1;
while (x){
if (x&1) product_mod(ans, a, n, mod);
product_mod(a, a, n, mod);
x >>= 1;
}
}
ll a[N][N];
int bits[N];

void init(){
for (int i = 0; i < 4; i++)
bits[i] = (1<<i);
memset(a,0,sizeof(a));
int tmp;
for (int i = 0; i < 16; i++){
a[i][(~i & 0xf)] = 1;
tmp = (~i & 0xf);
for (int j = 0; j < 3; j ++){
if ((tmp & bits[j]) == 0 && (tmp & bits[j + 1]) == 0){
a[i][tmp | bits[j] | bits[j+1]] = 1;
}
}
}
a[15][15] = 1;
/*for (int i = 0; i < 16; i++){
for (int j = 0; j < 16; j++)
cout << a[i][j] << &#39; &#39; ;
cout << endl;
}*/
}

int main(){
int n, mod;
while (~scanf("%d%d", &n, &mod) && (n + mod)){
init();
power_mod(a, n, 16, (long long)mod);
printf("%lldn", ans[15][15]);
}
return 0;
}

用矩阵表示状态的转移

位运算计算下一行的状态

两个能够转化的连接一条边

dp[i][x][y] 表示前i个已经完成匹配并且i+1为x,i+2为y的时候的最小变化次数

因为第i个是肯定要变的,然后后面的两个数的变换次数分别有up >= k >= l (up为i的变化,k为i+1的变换,l为i+2的变换)或者down >= k >= l

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* From: Lich_Amnesia
* Time: 2013-12-16 19:14:28
*
* HDU 4433 DP
* */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
using namespace std;

const int INF = 100000000;
typedef pair <int,int> P;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
#define maxn 1010

char s[maxn],t[maxn];
int dp[maxn][12][12];
int a[maxn],b[maxn];
int main(){
while (~scanf("%s%s", s, t)){
for (int i = 0; i <= strlen(s); i ++)
for (int j = 0; j < 10; j ++)
for (int l = 0; l < 10; l ++)
dp[i][j][l] = INF;

for (int i = 0; i < strlen(s); i++){
a[i+1] = s[i] - &#39;0&#39;;
b[i+1] = t[i] - &#39;0&#39;;
}
int len = strlen(s);
a[len + 1] = a[len + 2] = 0;
b[len + 1] = b[len + 2] = 0;

dp[0][a[1]][a[2]] = 0;

for (int i = 1; i <= len; i ++){
for (int x = 0; x < 10; x++){
for (int y = 0; y < 10; y++){
int down = (x + 10 - b[i]) % 10;
for (int k = 0; k <= down; k++)
for (int l = 0; l <= k; l++){
dp[i][(y-k+10)%10][(a[i+2]-l+10)%10] =
min(dp[i-1][x][y] + down,
dp[i][(y-k+10)%10][(a[i+2]-l+10)%10]);
}
int up = 10 - down;
for (int k = 0; k <= up; k++)
for (int l = 0; l <= k; l++){
dp[i][(y+k)%10][(a[i+2]+l)%10] =
min(dp[i-1][x][y] + up,dp[i][(y+k)%10][(a[i+2]+l)%10]);
}
}
}
}
printf("%dn", dp[len][0][0]);
}
return 0;
}

画图找规律

f[1] = 2
f[n] = f[n-1] + 1 + f[n-1] + 1 + f[n-1]
f[n] = 3^n - 1 快速幂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <cmath>
#include <cstdio>

using namespace std;
typedef long long ll;

ll quick_mod(ll n, ll k, ll mod){
ll ret = 1;
while (k){
if (k&1) ret = (ret * n) % mod;
k >>= 1;
n = (n*n) % mod;
}
return ret;
}

int main(){
ll n,m;
cin >> n >> m;
cout << (quick_mod(3,n,m) - 1 + m) % m<< endl;
return 0;
}

做一个映射表第一次出现的位置就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstdio>
using namespace std;
typedef long long ll;
#define maxn 100010
int a[maxn],b[maxn];
map<int,int>map1,map2;
bool cmp(int a,int b){
return a > b;
}
int main(){
int n,m;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
b[n - i - 1] = a[i];
}
int num = 1;
for (int i = 0; i < n; i++){
if (map1[a[i]] == 0) map1[a[i]] = i + 1;
}

for (int i = 0; i < n; i++){
if (map2[b[i]] == 0) map2[b[i]] = i + 1;
}
cin >> m;
int cnt;
ll ansmin = 0,ansmax = 0;
for (int i = 0; i < m; i++){
cin >> cnt;
if (map1[cnt] == 0) ansmin += n;
else ansmin += map1[cnt];
if (map2[cnt] == 0) ansmax += n;
else ansmax += map2[cnt];
}
cout << ansmin << &#39; &#39; << ansmax << endl;
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <cmath>
#include <cstdio>

using namespace std;
typedef long long ll;
ll x[10],y[10];

int main(){
cin >> x[0] >> y[0];
cin >> x[1] >> y[1];
cin >> x[2] >> y[2];
x[3] = x[1] - x[0];y[3] = y[1] - y[0];
x[4] = x[2] - x[1];y[4] = y[2] - y[1];
ll ans = x[3] * y[4] - x[4] * y[3];
if (ans > 0) printf("LEFTn");
else if (ans < 0) printf("RIGHTn");
else printf("TOWARDSn");
return 0;
}

想象成一个树,然后有一个递归关系,

1.如果这个点src的子树中有一个含有2号边那就不用管直接return 1表示这个以src为根的子树已经判定完毕

2.如果这个点src正好是叶子节点那么就返回[src][pre]这条边的值,1表示需要修理,并且存下这个src必须得需要它这个点

3.如果这个src的子树中没有含有2号点的证明src下面的树中没有需要修理的。

两种情况:第一个是src和pre这条边是2号边那就return 1,表示这个点src是答案中的。第二个是如果src和pre的是1号边那么就return 0,不需要修理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <algorithm>
#include <map>
#include <cstdio>
#include <set>
#include <cstring>
#include <vector>
using namespace std;

struct edge{
int u,t;
}tmp;

#define maxn 100010
vector <edge> ve[maxn];
bool vis[maxn];
int ans[maxn],ansnum = 0;

bool solve(int src, int pre, int flag){
vis[src] = 1;
int cnt = 0;
int ret = -1;
int sumret = 0;
for (int i = 0; i < ve[src].size(); i ++){
//if (ve[src][i].u == pre) yeziret = ve[src][i].t ;
if (!vis[ve[src][i].u]){
ret = solve(ve[src][i].u,src,ve[src][i].t);
sumret += ret;
}
else cnt ++;
if (i == ve[src].size() - 1 && sumret == 0 && flag == 1 && cnt != ve[src].size()){
ans[ansnum ++] = src;
return flag;
}
if (i == ve[src].size() - 1 && cnt != ve[src].size()) return sumret;
}
if (cnt == ve[src].size()){
if (flag) ans[ansnum ++] = src;
return flag;
}
}

int main(int argc, char const *argv[])
{
int n,u,v,t;
memset(vis,0,sizeof(vis));
scanf("%d", &n);
for (int i = 0; i < n - 1; i++){
scanf("%d%d%d", &u, &v, &t);
tmp.u = v;
tmp.t = t - 1;
ve[u].push_back(tmp);
tmp.u = u;
tmp.t = t - 1;
ve[v].push_back(tmp);
}
solve(1,1,0);
printf("%dn", ansnum);
for (int i = 0; i < ansnum; i++)
printf("%d ", ans[i]);
return 0;
}

分成k和n-k的部分,然后算sk/k 和(sall - sk) /(n - k),易知,前面的k个数肯定是比较大的,然后前面k个进行均分sk%k的值在前k中分配且要不能大于r,然后后面的n-k也是一样的只是不能大于a[k]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <algorithm>
#include <map>
#include <cstdio>
using namespace std;
int a[1010];
int main(int argc, char const *argv[])
{
int n,k,l,r,sall,sk;
scanf("%d%d%d%d%d%d", &n, &k, &l, &r, &sall, &sk);
int Maxn = sk / k;
int Maxmod = sk % k;
for (int i = 0; i < k; i++){
a[i] = Maxn;
if (Maxmod){
if (Maxmod + a[i] >= r) {
Maxmod -= r - a[i];
a[i] = r;
}else {
a[i] += Maxmod;
Maxmod = 0;
}
}
}
if (n > k){
Maxn = (sall - sk) / (n-k);
Maxmod = (sall - sk) % (n-k);

for (int i = k; i < n; i++){
a[i] = Maxn;
if (Maxmod){
if (Maxmod + a[i] >= a[k-1]) {
Maxmod -= a[k-1] - a[i];
a[i] = a[k-1];
}else {
a[i] += Maxmod;
Maxmod = 0;
}
}
}
}
for (int i = 0; i < n; i ++){
printf("%d ", a[i]);
}

return 0;
}

判定1,2。算一下 有没有可以用的盘子或者碗,然后加减一下就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <algorithm>
#include <map>
#include <cstdio>
using namespace std;
int a[1010];
int main(int argc, char const *argv[])
{
int n,m,k;
scanf("%d%d%d", &n, &m, &k);
int bow = m, plat = k;
int ans = 0;
for (int i = 0; i < n; i ++){
scanf("%d", &a[i]);
if (a[i] == 1) {
if (bow) bow --;
else ans ++;
}else {
if (plat) {
plat --;
}else if (bow){
bow --;
}else ans ++;
}
}
cout << ans << endl;

return 0;
}

找出规律,最后一位对数据的影响只在和最前一位的大小关系上,然后去掉最后一位其他的都是可行的,最后加上1-9。