李聪的博客

少年易老学难成,一寸光阴不可轻


  • 首页

  • 标签

  • 分类

  • 归档

Codeforces -908D

发表于 2018-03-18 | 分类于 ACM

题解

$dp[i][j]$表示有$i$个$a$,j个ab时的期望,可得转移方程
$$
dp[i][j]={dp[i+1][j]\times pa +\\
dp[i][j+i]\times pb}
$$
(注意这里需要求的是期望,当前状态的期望由它可能到达的状态求得,而不是能到达它的状态求得)
当$i+j>=k$时,只要末尾中再出现一个$b$,此时的ab子序列个数就变成了$i+j$个,而$i+j>=k$,满足了题目条件。当末尾得到一个$a$时,继续添加,当得到一个$b$时,添加的过程停止。因此当停止时添加的字符个数(包括最后一个$b$)的期望为$1\over pb$(每次有pb的概率停止,那么使过程停止的期望次数是$1\over pb$。类似一个人投篮,每次有$p={2\over 3}$的概率投中,那他投中一次的所需要的投篮次数的期望为${1\over p}=1.5$次),$1\over pb$个字符中,1个b,${1\over pb}-1$个a,则等于增加了${1\over pb}-1={ {1-pb}\over pb}={pa\over pb}$个$ab$子序列
因此可以得出总的方程
$$
\begin{cases}
dp[i][j]={dp[i+1][j]\times pa +\\ dp[i][j+i]\times pb} & i+j<k \\
dp[i][j]=i+j+{pa\over pb} & i+j\ge k
\end{cases}
$$

代码

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
#include "stdio.h"
#include "cstring"
#include "stdlib.h"
#include "map"
#include "string"
#include "iostream"
#include "set"
#include "queue"
#include "list"
#include "vector"
#include "algorithm"
#define FOP freopen("input.txt","r",stdin)
#define Met(x,y) memset(x,y,sizeof x)
using namespace std;
typedef long long ll;
const ll MAXN=2e3+100;
const ll MOD=1e9+7;

void exgcd(ll a,ll b,ll& d,ll& x,ll& y)
{
if(!b) { d = a; x = 1; y = 0; }
else{ exgcd(b, a%b, d, y, x); y -= x*(a/b); }
}

ll inv(ll a) //a 关于 mod MOD除法的逆元
{
ll d, x, y;
exgcd(a, MOD, d, x, y);
return d == 1 ? (x+MOD)%MOD : -1;
}
ll dp[MAXN][MAXN];
int main(int argc, char const *argv[]) {
ll n,n1,n2;
cin>>n>>n1>>n2;
ll pa=n1*inv(n1+n2)%MOD;
ll pb=n2*inv(n1+n2)%MOD;
ll pbi=inv(pb);
// ll ans=0;
Met(dp,0);
for(int i=n;i>0;--i)
{
for(int j=n-i;j>=0;--j)
{
if(i+j==n) dp[i][j]=(i+j+pa*pbi)%MOD;
else dp[i][j]=(dp[i+1][j]*pa%MOD + dp[i][j+i]*pb%MOD)%MOD;
}
}
cout<<dp[1][0]<<endl;
return 0;
}

牛客练习赛13 幸运数字Ⅳ

发表于 2018-03-18 | 分类于 ACM

思路

这种题目需要仔细观察,来判断出真正的数据范围,$n$个数排列的情况数,也就是$n!$,随$n$增大是非常快的。因为$15!>1e9$,所以当长度大于15时,只要计算最后15个数的第$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
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "stdio.h"
#include "cstring"
#include "stdlib.h"
#include "map"
#include "string"
#include "iostream"
#include "set"
#include "queue"
#include "vector"
#define FOP freopen("input.txt","r",stdin)
#define Met(x,y) memset(x,y,sizeof x)
#define L index*2
#define R index*2+1
using namespace std;
typedef long long ll;
const ll MAXN=5e5+100;
const ll MOD=1e9+7;
ll fra[20];
void init()
{
fra[0]=1;
for(int i=1;i<20;++i)
fra[i]=fra[i-1]*i;
// cout<<fra[15]<<endl;
}
ll calu(ll lim)
{
bool ret=0;
ll res=0;
for(int i=1;i<=12 && !ret;++i)
for(int j=0;j<(1<<i) && !ret;++j)
{
ll digit=1;
ll tem=j;
ll cs=0;
for(int k=0;k<i;++k)
{
if(tem%2)
cs+=digit*7;
else cs+=digit*4;
tem/=2;
digit*=10;
}
if(cs<=lim) res++;
if(cs>=lim) ret=0;
}
return res;
}
ll permute[20];
bool judge(ll num)
{
while (num) {
if(num%10!=4 && num%10!=7)
return 0;
num/=10;
}
return 1;
}
int main(int argc, char const *argv[]) {
// FOP;
init();
ll n,kth;
cin>>n>>kth;
ll ans=calu(n- 15);
// cout<<ans<<endl;
ll digit=min(15LL,n);
bool used[20];
Met(used,0);
kth--;
for(int i=0;i<digit;++i)
{
ll tem=kth/fra[digit-i-1];
// printf("%lld %lld\n", kth,fra[digit-i-1]);
kth%=fra[digit-i-1];
// printf("%lld %lld\n", kth,fra[digit-i-1]);
if(tem>=digit-i)
{
puts("-1");
return 0;
}
for(int j=0;j<20;++j)
{
if(used[j])
continue;
if(!tem)
{
permute[i]=j;
used[j]=1;
break;
}
tem--;
}
// for(int j=0;j<20;++j)
// printf("%d ",used[j]);
// puts("");
// printf("%lld\n",permute[i]+1);
}
ll cnt=0;
for(int i=max(1LL,n-14),cnt=0;i<=n;++i,cnt++)
{
// cout<<max(1LL,n-14)+permute[i-max(1LL,n-14)]<<endl;
// cout<<i<<endl;
ans+=judge(max(1LL,n-14)+permute[i-max(1LL,n-14)])&judge(i);
}
cout<<ans<<endl;
return 0;
}

ZOJ 4008 Yet Another Tree Query Problem

发表于 2018-03-14 | 分类于 ACM

题意

给一颗树,q个询问,每个询问求节点标号$[l,r]$之间的节点组成的连通块的个数。

题解

首先这个图是一棵树,$[l,r]$连通块的个数就是$r-l+1-e$($e$为两点标号都在$[l,r]$的边的个数)
把每条边编号大的点放入树状数组。
然后把询问按$l$从小到大排序。
之后从1到n枚举左端点,每轮循环最后把左端点在$i$的边从树状数组中删除。这样树状数组中的边的左端点总是大于$i$,因此当i枚举到每个询问的$l$时,sum(r)就是两点标号都在$[l,r]$的边的个数)

总结

看到图是树一定要想到树的特点和性质,这道题树状数组依然是应用到了之前总结的树状数组解决两个不等式限制问题,但自己还是没有想到。

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
#include <cstdio>
#include <cstring>
#include <algorithm>
#include "iostream"
#include <cmath>
#include <vector>
#include "set"
using namespace std;
#define FOP freopen("input.txt","r",stdin)
#define Met(x,y) memset(x,y,sizeof x)
typedef long long ll;
const ll INF = 1e18;
const ll MAXN =2e5+100;
const ll MOD = 1e9+7;

ll BIT[MAXN],n;
ll Lowbit(ll x) // 2^k
{
return x&(-x);
}
void update(ll i, ll x)//i点增量为x
{
while(i <= n)
{
BIT[i] += x;
i += Lowbit(i);
}
}
ll sum(ll x)//区间求和 [1,x]
{
ll sum=0;
while(x>0)
{
sum+=BIT[x];
x-=Lowbit(x);
}
return sum;
}
vector<ll> lp[MAXN];
void init()
{
for(int i=0;i<MAXN;++i)
lp[i].clear();
Met(BIT,0);
}
struct Ele{
ll l,r,id;
bool operator < (const Ele &a)const{
return l<a.l;
}
}que[MAXN];
ll ans[MAXN];
int main(int argc, char const *argv[]) {
ll m;
ll T_T;
cin>>T_T;
while(T_T--)
{
init();
cin>>n>>m;
for(int i=1;i<n;++i)
{
ll u,v;
scanf("%lld%lld",&u,&v);
update(max(v,u),1);
lp[min(u,v)].push_back(max(u,v));
}
for(int i=0;i<m;++i)
{
scanf("%lld%lld",&que[i].l,&que[i].r);
que[i].id=i;
}
sort(que,que+m);
ll cur=0;
for(int i=1;i<=n;++i)
{
while (cur<m && que[cur].l==i) {
ans[que[cur].id]=que[cur].r-que[cur].l+1-sum(que[cur].r);
cur++;
}
for(int j=0;j<lp[i].size();++j)
update(lp[i][j],-1);
}
for(int i=0;i<m;++i)
printf("%lld\n", ans[i]);
}
return 0;
}

Codeforces 912D Fishes

发表于 2018-03-14 | 分类于 ACM

思路

靠中间的位置自然是最好的,可以用一个函数计算出一个位置对答案的贡献。建立一个按贡献排序的优先队列,先把最中间的位置放入。
然后进行取出,每取出一个,就把它相邻且没有放入过的元素放入优先队列,这样取出k个,就是最优的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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include "stdio.h"
#include "cstring"
#include "stdlib.h"
#include "map"
#include "string"
#include "iostream"
#include "set"
#include "queue"
#include "list"
#include "vector"
#include "algorithm"
#define FOP freopen("input.txt","r",stdin)
#define Met(x,y) memset(x,y,sizeof x)
using namespace std;
typedef long long ll;
const ll MAXN=2e5+100;
const ll MOD=1e9+7;

struct gridc{
ll x,y;
ll ct;
bool operator < (const gridc &a)const{
return ct<a.ct;
}
gridc(ll xx,ll yy,ll cct):x(xx),y(yy),ct(cct){}
};
ll p,q,n,m,k;
struct grid{
ll x,y;
bool operator < (const grid &a)const{
return x*(ll)1e5+y<a.x*(ll)1e5+a.y;
}
grid(ll xx,ll yy):x(xx),y(yy){}
};
ll getct(ll x,ll y)
{
ll ax,ay,bx,by;
ax=max(0LL,x-p+1);
ay=max(0LL,y-q+1);
bx=min(n-q,x);
by=min(m-q,y);
return (bx-ax+1)*(by-ay+1);
}
priority_queue<gridc> pq;
set<grid> vis;
ll dir[4][2]={-1,0,1,0,0,1,0,-1};
int main(int argc, char const *argv[]) {
// FOP;
cin>>n>>m>>p>>k;
q=p;
pq.push(gridc(n/2,m/2,getct(n/2,m/2)));
vis.insert(grid(n/2,m/2));
ll tct=0;
for(int i=0;i<k;++i)
{
tct+=pq.top().ct;
gridc cur=pq.top();
pq.pop();
// printf("x=%lld y=%lld ct=%lld\n",cur.x,cur.y,cur.ct);
for(int j=0;j<4;++j)
{
ll nx=cur.x+dir[j][0],ny=cur.y+dir[j][1];
if(nx<0 || nx>=n || ny<0 || ny>=m || vis.count(grid(nx,ny))) continue;
vis.insert(grid(nx,ny));
// printf("nx=%lld ny=%lld ct=%lld\n", nx,ny,getct(nx,ny));
pq.push(gridc(nx,ny,getct(nx,ny)));
}
}
printf("%.10lf",(double)tct/((n-p+1)*(m-p+1)));
return 0;
}

排列组合n球放m盒问题

发表于 2018-03-10 | 分类于 ACM

球同,盒不同,没有空盒

把 $n$ 个球排成一排,它们中间有 $n-1$ 个空。取 $m-1$ 个板,放到空上,就把它们分成 $m$ 部分,由于板不相邻,所以没有空盒。它的方法数有 $$C_{n-1}^{m-1}$$

球同,盒不同,可以有空盒

在上个问题的基础上,假设把 $n+m$ 个球放到 $m$ 个盒子里没有空盒,再从每个盒子里拿走一个球,就是可以有空盒的情况,它的方法数有 $$C_{n+m-1}^{m-1}$$

HDU-6230 HDU-5542 利用树状数组解决两个不等式限制的问题

发表于 2018-02-10 | 分类于 ACM

两道题目运用了类似的思路,因此写在一起总结下。

HDU-6230

题目大意

给出长度为n的序列,问这个序列中有多少个长度为m的单调递增子序列。

解题思路

设 $DP[i][j]$ 表示长度为 $i$ ,最后一位为 $a[j]$ 的字符串个数
可以得到以下递推公式
$$
DP[i][j]=\sum_{k=i-2}^{j-1} DP[i-1][k]\space\space\space(a[k]<a[j])
$$
普通的算法时间复杂度为 $n^3$ ,无法满足要求
可以发现这个式子有两个不等式限制
$$
\begin{cases}
i-2<=k<=j-1 \\
a[k]<a[j]
\end{cases}
$$
即可在循环中每次最后把 $DP[i-1][j]$ 放入 $Bit[a[j]]$
下次循环中$j$增大,此时树状数组中的元素都满足第一个限制
在每次查询中求 $sum(a[j])$ 即满足第二个限制(此时 $Bit[a[j]]$ 位还没有放入)

HDU-5542

前面部分略过不讲,只关注最后不等式部分
需要求解有多少 $i,j$ 满足

$$
\begin{cases}
i<j\\
p[i]\leq j-i\\
p[j]\leq j-i
\end{cases}
$$

整理成

$$
\begin{cases}
i\geq j-p[j]\\
i<j\leq i+p[i]
\end{cases}
$$

每次循环把满足 $j-p[j]=i$ 的 $j$ 放入树状数组(借助vector<ll> g[])
随循环继续,$i$ 增大,此时树状数组中的元素都满足第一个限制
在每次查询中求 $sum(i+p[i])-sum(i)$ 即满足第二个限制

C++的几种常用STL的用法,map,set,priority_queue

发表于 2018-01-07 | 分类于 ACM

网上类似的博客有很多,我写这个博客主要是为了帮助自己和大家记住STL这几个容器相关的语法

  • 结构体的排序

    • 这三个容器都要求其中的元素可以排序,当插入元素为结构体时,需要通过重载运算符为结构体自定义排序方法。

      1
      2
      3
      4
      5
      6
      struct S{
      ll id,v;
      bool operator< (const S &a)const{
      return v<a.v;
      }
      }s[100];

      若对s结构体数组赋值后排序,则从左到右v依次增大
      可以理解为v代表左边那个,以参数形式传入的a.v代表右边那个,执行完排序之后,结构体中相邻两个元素满足return中的条件,上面的代码可以理解为排序之后左边的v<右边的v

  • set

    • C++的set是利用平衡二叉树实现的一个容器,具有以下特点

      1. 对于插入、删除和查找操作,set保证其时间复杂度都是$O(\log_2n)$(n是set中元素的个数)。
      2. set是一个有序的、可以前向和后向遍历的容器(双向迭代器)。
      3. set的元素可以插入、删除,但是不可更改。
      4. set中的元素不可重复。

      至于具体的原理去学习一下二叉排序树和平衡二叉树就会了解了

    • 插入

      • 1
        .insert();
    • 删除

      • 1
        .erase();
    • 判断是否存在

      • 1
        .count();

        count()本来是STL中用来判断某个元素出现多少次的函数,由于set中元素不能重复,返回值为0或1。

    • 遍历

      • 1
        2
        3
        4
        5
        6
        7
        set<int> s;
        int main(int argc, char const *argv[]) {
        for(int i=0;i<10;++i)
        s.insert(i);
        for(std::set<int>::iterator it=s.begin();it!=s.end();++it)
        cout<<*it<<" ";
        }

        C++11的新语法遍历(Range-based for loop)

        1
        2
        3
        4
        5
        6
        7
        set<int> s;
        int main(int argc, char const *argv[]) {
        for(int i=0;i<10;++i)
        s.insert(i);
        for(auto &v:s)
        cout<<v<<" ";
        }

        输出均为

        1
        0 1 2 3 4 5 6 7 8 9
    • 反向遍历

      • 1
        2
        3
        4
        5
        6
        7
        set<int> s;
        int main(int argc, char const *argv[]) {
        for(int i=0;i<10;++i)
        s.insert(i);
        for(std::set<int>::reverse_iterator rit=s.rbegin();rit!=s.rend();++rit)
        cout<<*rit<<" ";
        }
    • 遍历删除

      • 1
        2
        for(set<int>::iterator it=s.begin();it!=s.end();)
        s.erase(it++);
    • 选择性遍历删除

      • 1
        2
        3
        4
        for(set<int>::iterator it=s.begin();it!=s.end();)
        if((*it)%2)
        s.erase(it++);
        else it++;

        删除set中的奇数

    • 设置排序优先级

      • int或long long

        • 默认从小到大
          使用

          1
          set <int, greater<int> > setTest;

          可以从大到小排序(可以理解为左边的大,所以叫greater)

      • 结构体使用上文说的重载运算符来设置排序优先级
  • map

    • c++11新语法遍历

      1
      2
      3
      4
      5
      for(auto &kv:a)
      {
      cout<<kv.first;
      cout<<kv.second;
      }
    • 普通遍历

      1
      2
      3
      for (auto it = num_map.begin(); it != num_map.end(); ++it) {
      std::cout << it->first << ", " << it->second << '\n';
      }
  • priority_queue

    • 排序

      排序方法与set相同,但使用.top()函数时返回的是最右边的元素。

      1
      std::priority_queue<int, std::vector<int>, std::greater<int> >

      默认同样是左小右大,当需要左大右小是使用上面的语法。

    • 函数

      1
      2
      .top();
      .push();

教学计划编制问题

发表于 2018-01-03

LinkQueue.h

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
89
90
91
92
93
94
95
96
97
98
99
100
101
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
#define QElemType int

//链队列结点结构
struct LinkNode {
QElemType data;
LinkNode *next;
};

//带头结点的链队列结构
struct LinkQueue {
LinkNode *front; //队头指针
LinkNode *rear; //队尾指针
};

//构造一个空的链队列。
void InitQueue( LinkQueue &Q )
{
Q.front = Q.rear = new LinkNode;
Q.front->next = NULL;
}//LinkQueue

//将链队列清空。
void ClearQueue( LinkQueue &Q )
{
LinkNode *p;
while ( Q.front->next != NULL )
{
p = Q.front->next;
Q.front->next = p->next;
delete p;
}
Q.rear = Q.front;
}

//链队列结构销毁。
LinkQueue DestroyQueue( LinkQueue &Q )
{
ClearQueue( Q ); //成员函数Clear()的功能是释放链表中的所有元素结点
delete Q.front;
Q.front = Q.rear = NULL;
}

//判链队列是否为空,若为空,则返回true,否则返回false。
bool QueueEmpty( LinkQueue Q )
{
return Q.front == Q.rear;
}

//返回链队列中元素个数。
int QueueLength( LinkQueue Q )
{
int i = 0;
LinkNode *p = Q.front->next;
while ( p != NULL )
{
i++;
p = p->next;
}
return i;
}

//取链队列队头元素的值。先决条件是队列不空。
QElemType GetHead( LinkQueue &Q )
{
return Q.front->next->data;
}

//取链队列队尾元素的值。先决条件是队列不空。
QElemType GetLast( LinkQueue &Q )
{
return Q.rear->data;
}

//链队列入队,插入e到队尾。
void EnQueue( LinkQueue &Q, QElemType e )
{
LinkNode *p;
p = new LinkNode ;
p->data = e;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
}

//链队列出队。先决条件是队列不空。
bool DeQueue( LinkQueue &Q,QElemType &e )
{
if ( QueueEmpty( Q ) )
return false;
LinkNode *p = Q.front->next;
Q.front->next = p->next;
e = p->data;
if ( p == Q.rear )
Q.rear = Q.front; //若出队后队列为空,需修改Q.rear。
delete p;
return true;
}

#endif

教学计划编制问题.cpp

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "stdio.h"
#include "cstring"
#include "stdlib.h"
#include "map"
#include "string"
#include "stack"
#include "LinkQueue.h"
#include "iostream"

using namespace std;
typedef long long ll;

const int MAXN=200;

struct ArcBox{
int tailvex,headvex;
ArcBox *hlink,*tlink;
};

struct VexNode{
ArcBox *firstin,*firstout;
// int credit;
};
struct Graph{
VexNode xlist[MAXN];
int vexnum,arcnum;
}G;

void addedge(int v1,int v2)
{
ArcBox *p=(ArcBox *)malloc(sizeof(ArcBox));
*p={v1,v2,G.xlist[v2].firstin,G.xlist[v1].firstout};
G.xlist[v2].firstin=G.xlist[v1].firstout=p;
}
std::map<string,int> CourseToId;
LinkQueue que[2];
char IdToCourse[MAXN][20];
int in[MAXN];
int list[MAXN];
int credit[MAXN];
bool vis[MAXN];
int main(int argc, char const *argv[]) {
// freopen("input.txt","r",stdin);
memset(in,0,sizeof in);
memset(vis,0,sizeof vis);
CourseToId.clear();
for(int i=0;i<2;++i)
InitQueue(que[i]);
int index=0;
int sumcredit=0;

int numSemaster,creditlim,numCourse,numedge;
printf("请输入学期数,学分上限,课程数,前置课程限制数\n" );
scanf("%d%d%d%d",&numSemaster,&creditlim,&numCourse,&numedge);
G.vexnum=numCourse; G.arcnum=numCourse;
for(int i=0;i<G.vexnum;i++) G.xlist[i].firstin=NULL,G.xlist[i].firstout=NULL;
printf("请输入课程名和学分\n" );
for(int i=0;i<numCourse;++i)
{
scanf("%s %d",IdToCourse[i],&credit[i]);
sumcredit+=credit[i];
CourseToId[IdToCourse[i]]=i;
}
printf("请输入课程的前置课程和该课程\n" );
for(int i=0;i<numedge;++i)
{
char c1[100],c2[100];
scanf("%s %s",c1,c2);
int p1=CourseToId[c1];
int p2=CourseToId[c2];
addedge(p1,p2);
in[p2]++;
}
ll nin[MAXN],sin[MAXN];
for(int i=0;i<numCourse;++i) sin[i]=in[i];

printf("finish all course as fast as possible\n" );
ll cnt=1;
int curque=0;
for(int i=0;i<numCourse;++i)
if(!in[i]) EnQueue(que[curque],i);
while(cnt<=numSemaster)
{
if(QueueEmpty(que[curque])) break;
printf("Semaster %I64d: ",cnt);
// for(ll i=0;i<numCourse;++i) nin[i]=in[i];
ll curcredit=0;
// for(int i=0;i<numCourse && curcredit<creditlim;++i)
while(!QueueEmpty(que[curque]) && curcredit<creditlim)
{
int u=GetHead(que[curque]);
if(curcredit+credit[u]<=creditlim)
{
// vis[u]=1;
int tem;
DeQueue(que[curque],tem);
curcredit+=credit[u];
printf("%s ",IdToCourse[u]);
for(ArcBox *p=G.xlist[u].firstout;p!=NULL;p=(*p).tlink)
{
int v=(*p).headvex;
in[v]--;
if(!in[v])
EnQueue(que[!curque],v);
}
}
}
while(!QueueEmpty(que[curque])) {
int tem;
DeQueue(que[curque],tem);
EnQueue(que[!curque],tem);
}
curque=!curque;
puts("");
cnt++;
}
for(int i=0;i<numCourse;++i) in[i]=sin[i];
// for(int i=0;i<2;++i)
// ClearQueue(que[i]);
curque=0;
for(int i=0;i<numCourse;++i)
if(!in[i]) EnQueue(que[curque],i);
printf("make the credit of each semaster as equivalent as possible\n" );
double ave=sumcredit/(double)numSemaster;
cnt=1;
ll cursumcredit=0;
while(cnt<=numSemaster)
{
if(QueueEmpty(que[curque])) break;
printf("Semaster %lld: ",cnt);
ll curcredit=0;
while(!QueueEmpty(que[curque]) && curcredit<creditlim)
{
// printf("test\n" );
int u=GetHead(que[curque]);
if(curcredit+credit[u]<=creditlim && cursumcredit+credit[u]<=ave*cnt)
{
// vis[u]=1;
int tem;
DeQueue(que[curque],tem);
curcredit+=credit[u];
cursumcredit+=credit[u];
printf("%s ",IdToCourse[u]);
for(ArcBox *p=G.xlist[u].firstout;p!=NULL;p=(*p).tlink)
{
int v=(*p).headvex;
in[v]--;
if(!in[v])
EnQueue(que[!curque],v);
}
}else break;
}
while(!QueueEmpty(que[curque])){
int tem;
DeQueue(que[curque],tem);
EnQueue(que[!curque],tem);
}
curque=!curque;
puts("");
cnt++;
}
return 0;
}

魔王的语言

发表于 2018-01-02

LinkQueue.h

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
89
90
91
92
93
94
95
96
97
98
99
100
101
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_
#define QElemType char

//链队列结点结构
struct LinkNode {
QElemType data;
LinkNode *next;
};

//带头结点的链队列结构
struct LinkQueue {
LinkNode *front; //队头指针
LinkNode *rear; //队尾指针
};

//构造一个空的链队列。
void InitQueue( LinkQueue &Q )
{
Q.front = Q.rear = new LinkNode ;
Q.front->next = NULL;
}//LinkQueue

//将链队列清空。
void ClearQueue( LinkQueue &Q )
{
LinkNode *p;
while ( Q.front->next != NULL )
{
p = Q.front->next;
Q.front->next = p->next;
delete p;
}
Q.rear = Q.front;
}

//链队列结构销毁。
LinkQueue DestroyQueue( LinkQueue &Q )
{
ClearQueue( Q ); //成员函数Clear()的功能是释放链表中的所有元素结点
delete Q.front;
Q.front = Q.rear = NULL;
}

//判链队列是否为空,若为空,则返回true,否则返回false。
bool QueueEmpty( LinkQueue Q )
{
return Q.front == Q.rear;
}

//返回链队列中元素个数。
int QueueLength( LinkQueue Q )
{
int i = 0;
LinkNode *p = Q.front->next;
while ( p != NULL )
{
i++;
p = p->next;
}
return i;
}

//取链队列队头元素的值。先决条件是队列不空。
QElemType GetHead( LinkQueue &Q )
{
return Q.front->next->data;
}

//取链队列队尾元素的值。先决条件是队列不空。
QElemType GetLast( LinkQueue &Q )
{
return Q.rear->data;
}

//链队列入队,插入e到队尾。
void EnQueue( LinkQueue &Q, QElemType e )
{
LinkNode *p;
p = new LinkNode ;
p->data = e;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
}

//链队列出队。先决条件是队列不空。
bool DeQueue( LinkQueue &Q,QElemType &e )
{
if ( QueueEmpty( Q ) )
return false;
LinkNode *p = Q.front->next;
Q.front->next = p->next;
e = p->data;
if ( p == Q.rear )
Q.rear = Q.front; //若出队后队列为空,需修改Q.rear。
delete p;
return true;
}

#endif

SqStack.h

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
#ifndef _SqStack_
#define _SqStack_
#define SElemType char
//顺序栈结构
struct SqStack {
SElemType *base; //基地址指针
int top; //栈顶指针
int size; //向量空间大小
};

//栈的初始化,分配m个结点的顺序空间,构造一个空的顺序栈
void InitSqStack( SqStack &s, int m )
{
s.top = 0;
s.base = new SElemType[ m ];
s.size = m;
}

//栈销毁
void DestroySqStack( SqStack &s )
{
delete[] s.base;
s.top = 0;
s.size = 0;
}

//置空栈
void ClearSqStack( SqStack &s )
{
s.top = 0;
}

//判别栈是否为空
bool SqStackEmpty( SqStack s )
{
return s.top == 0;
}

//求栈中元素个数
int SqStackLength( SqStack s )
{
return s.top;
}

//取栈顶元素的值。先决条件是栈不空。
bool GetTop( SqStack s, SElemType &e )
{
if ( ! SqStackEmpty( s ) )
{
e = s.base[ s.top - 1 ];
return true;
}
else
return false;
}

//入栈,若栈满,则先扩展空间。插入e到栈顶
void PushSqStack( SqStack &s, SElemType e )
{
if ( s.top >= s.size )
{ //若栈满,则扩展空间。
SElemType *newbase;
newbase = new SElemType[ s.size + 10 ];
for ( int j = 0; j < s.top; j++ )
newbase[ j ] = s.base[ j ];
delete[] s.base;
s.base = newbase;
s.size += 10;
}
s.base[ s.top++ ] = e;
}

//出栈,先决条件是栈非空。
bool PopSqStack( SqStack &s, SElemType &e )
{
if ( SqStackEmpty( s ) )
return false;
e = s.base[ --s.top ];
return true;
}

#endif

魔王的语言

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
#include "stdio.h"
#include "SqStack.h"
#include "cstring"
#include "LinkQueue.h"

char str[100],ans[1000];
char strb[20]="tsaedsae";
char stra[20]="sae";
SqStack A;
LinkQueue B;
int main(int argc, char const *argv[]) {
while (printf("请输入魔王的语言: (输入数字0退出程序)\n" ),scanf("%s",str )!=EOF) {
if(str[0]=='0')
break;
int len=strlen(str);
InitSqStack(A,100);
InitQueue(B);
for(int i=0;i<len;++i)
{
if(str[i]=='A')
{
for(int j=0;j<strlen(stra);++j)
PushSqStack(A,stra[j]);
}else if (str[i]=='B') {
for(int j=0;j<strlen(strb);++j)
PushSqStack(A,strb[j]);
}else if(str[i]==')'){
char tem;
char rep;
while(PopSqStack(A,tem) && tem!='(')
{
EnQueue(B,tem);
rep=tem;
}
while (DeQueue(B,tem)) {
if(QueueLength(B)){
PushSqStack(A,rep);
PushSqStack(A,tem);
}else PushSqStack(A,rep);
}
}else{
PushSqStack(A,str[i]);
}
}
int index=0;
while(PopSqStack(A,ans[index++])){}
puts("翻译结果为:");
for(int i=index-2;i>=0;--i)
printf("%c", ans[i]);
puts("");
}
return 0;
}

2017年浙江工业大学大学生程序设计迎新赛决赛 F 栗酱的不等式

发表于 2017-12-28 | 分类于 ACM

题目描述

有不等式 $y\times x^3\le n$ ,已知 $y$ 为正整数,$x$ 为大于1的正整数,问当 $x$ 和 $y$ 的解数量刚好为 $m$ 的时候 $n$ 的最小值,如果不存在输出-1。

题解

观察到,答案是连续的(即随$m$增大,$n$也增大),同时对某个具体的$n$求出解数很容易,应由此想到二分答案$n$。对每一次二分中的$n$,枚举$x$,对每个$x$,有 $\lfloor {n\over x^3} \rfloor$种解数。

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
#include <cstdio>
#include <cstring>
#include <algorithm>
#include "iostream"
#include <cmath>
#include <vector>
#include "set"
#include "queue"
using namespace std;
#define FOP freopen("input.txt","r",stdin)
#define Met(x,y) memset(x,y,sizeof x)
typedef long long ll;
const ll INF = 1e18;
const ll MAXN = 5000+100;
const ll MOD = 1e9+7;

ll p3(ll a)
{
return a*a*a;
}
int main(int argc, char const *argv[]) {
ll m;
while(cin>>m)
{
ll ans=-1;
ll l=8,r=INF;
while(l<=r)
{
ll num=0,mid=(l+r)/2;
// printf("%lld %lld %lld\n", l,r,mid);
for(int i=2;i<INF && mid/p3(i);++i)
num+=mid/p3(i);
if(num==m) ans=mid;
if(num<m) l=mid+1;
else r=mid-1;
}
cout<<ans<<endl;
}
return 0;
}

1…345

李聪

44 日志
2 分类
18 标签
© 2018 李聪
由 Hexo 强力驱动 }
|
主题 — NexT.Pisces v5.1.3
访问人数 总访问量 次