今天是2019年暑假的最后一天,明天就开学了,时间过得真快啊!
一本通1618&LOJ10196:
【题意】:监狱有连续编号为 1 到 n 的 n 个房间,每个房间关押一个犯人。有 m 种宗教,每个犯人可能信仰其中一种。如果相邻房间的犯人信仰的宗教相同,就可能发生越狱。求有多少种状态可能发生越狱。
【思路】:首先,我们要知道:会发生越狱的状态数总状态数不会发生越狱的状态数,所以我们分两部分来解决此问题:
一、总状态数:有n个房间,每个房间有m种可能的状态,所以总状态数为。
二、不会发生越狱的状态数:第1个房间可以有m种状态,其余房间只能有种状态(除了上一个房间的那种状态),所以不会发生越狱的状态数为
综上所述,会发生越狱的状态数为,考虑到m和n都很大,直接计算会TLE,所以我们可以使用快速幂
【代码】:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=100003;
ll n,m;
ll ksm(ll a,ll b){//求a的b次方模mod的值
register ll res=1ll;
while (b){
if (b&1) res=res*a%mod;
a=a*a%mod;b>>=1;//记得每步取模
}
return res%mod;
}//快速幂的板子,考试是可以直接套进去
int main(){
cin>>m>>n;//输入也别输入反了啊
cout<<(ksm(m,n)-m*ksm(m-1,n-1)%mod+mod)%mod;
// 别忘了先加上mod再取模,因为ksm(m,n)可能小于m*ksm(m-1,n-1)%mod
return 0;
}
//附两组数据吧:
//Input1:1000 2100 Output1:71246
//Input2:1000000(别数了,6个0) 1000000000000(12个0) Output2:13558
//Input3:5 9 Output3:25397
一本通1602&LOJ10180:
【题意】:
烽火台是重要的军事防御设施,一般建在交通要道或险要处。一旦有军情发生,则白天用浓烟,晚上有火光传递军情。
在某两个城市之间有 n 座烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确传递,在连续 m 个烽火台中至少要有一个发出信号。现在输入 n,m 和每个烽火台的代价,请计算总共最少的代价在两城市之间来准确传递情报。
【思路】:dp,记f[i]表示第i个烽火台可以发出信号,则
时间复杂度:,当时,时间复杂度达到,会TLE
改写原方程式,得:,可以用单调队列优化,此时,时间复杂度降为
单调队列中应该保存有下标和f值,当然f不保存也可以,但保存了用起来方便
说一下单调队列的实现:可以手写一个队列,也可以用STL中的deque(双端队列,允许在两端快速删除和进入)
至于单调队列的原理、应用等和关于deque的知识,这里不在讲述,太长了,大家可以去网上搜索,或者有教科书的参考教科书
随便提一下,最后的答案并非f[n],因为最优解不一定要求第n个烽火台可以发出信号,但区间中又必须要有一个烽火台可以发出信号,所以最终答案应该是
至此,本题就可以顺利AC(不过,在LOJ上好像不用单调队列也可以AC,但可以用就用吧,节省时间,还可以练练单调队列,以免考试时忘了)
【代码】:
//The AC code by hpwwzyy2012
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+3e2;
struct node{
int subscr,value;
}q[N];int h,t,n,m,i,f[N],ans,a[N];
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
char c=0;int x=0;bool f=0;
while (!g(c)) f=c=='-',c=gc;
while (g(c)) x=x*10+c-48,c=gc;
return f?-x:x;
}
int main(){
// freopen("t1.in","r",stdin);
n=read();m=read();
for(i=1;i<=n;i++)
a[i]=read();
q[0].subscr=0;//初始化一下,不用应该也OK吧
for(i=1;i<=n;i++){
while (h<=t&&q[h].subscr<i-m) h++;//排除不可选的解
f[i]=f[q[h].subscr]+a[i];//此时,队头一定是可选的最优解
while (h<=t&&q[t].value>a[i]) t--;//排除可选但非最优解
q[++t]=(node){i,a[i]};//对于当前的单调队列而言,i一定是一个最优解
}
ans=0x3f3f3f3f;
for(i=n-m+1;i<=n;i++)
ans=min(ans,f[i]);
printf("%d",ans);
return 0;
}