The Preliminary Contest for ICPC Asia Nanchang 2019
B Fire-Fighting Hero
题目链接
题意:英雄从给定的s点出发,求到所有救火点的最短路径最大值。消防员从k个出发点随便选一个出发,求到所有救火点的最短路径最大值。将两个值进行比较。英雄乘以系数1/c,比较大小。对于救火点来说,其余救火点消防员跑到相对应的点最短路径,每个点具有一个值,求其最大值。
思路:读错题意,原本就是很普通最短路。
#include <bits/stdc++.h>
#define maxn 1005
using namespace std;
int n, m, s, k, c;
struct edge {
int to, cost;
};//定义边的结构体
typedef pair<int, int>P;//定义二元组 最短路径和顶点编号
vector <edge> G[maxn];//邻接表建图
int dis[maxn];//顶点最短路径
int di[maxn];
int v[maxn];
void dij(int a)
{
priority_queue<P, vector<P>, greater<P> >q;//优先队列logn
//可用fill(a,a+n,value)
memset(dis, 0x3f, sizeof(dis));//将dis数组设为最大值
dis[a] = 0;//起点为dis为0
q.push(P(0, a));
while (!q.empty())
{
P temp = q.top();
q.pop();
int v = temp.second;//获取最短路径顶点编号
if (dis[v]<temp.first)continue;//判断dis是否小于路径
for (int i = 0; i<G[v].size(); i++)
{
edge e = G[v][i];
if (dis[e.to]>dis[v] + e.cost)//压缩路径
{
dis[e.to] = dis[v] + e.cost;
q.push(P(dis[e.to], e.to));
}
}
}
}
void input() {
scanf("%d%d%d%d%d", &n, &m, &s, &k, &c);
int i, j;
for (i = 1; i <= n; i++)
G[i].clear();
for (i = 1; i <= k; i++)
scanf("%d", &v[i]);
int U, V, W;
for (i = 1; i <= m; i++)
{
scanf("%d%d%d", &U, &V, &W);
G[U].push_back( { V, W });
G[V].push_back( { U, W });
}
memset(di, 0x3f, sizeof di);
for (i = 1; i <= k; i++) {
dij(v[i]);
for (j = 1; j <= n; j++)
di[j] = min(di[j], dis[j]);
}
int v1=0,v2 = 0;
for (i = 1; i <= n; i++)
v2 = max(v2, di[i]);
dij(s);
for (i = 1; i <= n; i++)
v1 = max(v1, dis[i]);
if (v1 > v2*c)
printf("%d\n", v2);
else
printf("%d\n", v1);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
input();
// solve();
}
} C Hello 2019
题目链接
题意:给定字符串,包含9012但不包含8012的字符串为好字符串,问对于一个[l,r]区间的子字符串变为好字符串需要最少删去多少个字母。
思路:将2、0、1、9、8变为矩阵,在矩阵上递推dp删去个数,以线段树形式维护前缀
#include <bits/stdc++.h>
#define maxn 200005
using namespace std;
string s;
int n,m;
const int M=5;
struct Ma{
int a[M][M];
Ma(){
memset(a,0x3f,sizeof a);
}
Ma operator*(const Ma& b)const{
Ma ans;
for(int k=0;k<M;k++)
for(int i=0;i<M;i++)
for(int j=0;j<M;j++)
ans.a[i][j]=min(ans.a[i][j],a[i][k]+b.a[k][j]);
return ans;
}
};
struct node{
int l,r;
Ma a;
}t[maxn<<2];
void build(int l,int r,int rt){
t[rt].l=l;
t[rt].r=r;
if(l==r){
for(int i=0;i<M;i++)
t[rt].a.a[i][i]=0;
if(s[l]=='2'){
t[rt].a.a[0][0]=1;
t[rt].a.a[0][1]=0;
}
if(s[l]=='0'){
t[rt].a.a[1][1]=1;
t[rt].a.a[1][2]=0;
}
if(s[l]=='1'){
t[rt].a.a[2][2]=1;
t[rt].a.a[2][3]=0;
}
if(s[l]=='9'){
t[rt].a.a[3][3]=1;
t[rt].a.a[3][4]=0;
}
if(s[l]=='8'){
t[rt].a.a[3][3]=1;
t[rt].a.a[4][4]=1;
}
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
t[rt].a=t[rt<<1].a*t[rt<<1|1].a;
// cout<<"***"<<rt<<endl;
// for(int i=0;i<M;i++){
// for(int j=0;j<M;j++)
// {
// if(t[rt].a.a[i][j]==1061109567)
// cout<<"inf ";
// else
// cout<<t[rt].a.a[i][j]<<" ";
// }
// cout<<endl;
// }
//
// cout<<endl;
}
Ma query(int l,int r,int rt){
if(l<=t[rt].l&&t[rt].r<=r)
return t[rt].a;
int mid=(t[rt].l+t[rt].r)>>1;
if(mid>=r)
return query(l,r,rt<<1);
else if(mid<l)
return query(l,r,rt<<1|1);
else
return query(l,r,rt<<1)*query(l,r,rt<<1|1);
}
void input(){
scanf("%d%d",&n,&m);
cin>>s;
reverse(s.begin(),s.end());
s=" "+s;
build(1,n,1);
while(m--){
int x,y;
scanf("%d%d",&x,&y);
int l=n+1-y;
int r=n+1-x;
Ma temp=query(l,r,1);
int ans;
if(temp.a[0][4]>n)
ans=-1;
else
ans=temp.a[0][4];
printf("%d\n",ans);
}
}
int main(){
input();
} E Magic Master
题目链接
题意:桌子上有按顺序排列n张牌,我们需要循环进行以下操作,直到牌没有1、拿走第一张牌2、将最后一张牌拿到最前面的位置,循环m次。最终序列为1—n。求原序列下标的值。
思路:原序列经过以上步骤得到1-n。我们可以通过以上步骤得到此序列的倒置。模拟后,将查询离线排序。虽然时间复杂度算出来不对,但是依旧能神奇的过.
#include <bits/stdc++.h>
#define maxn 105
using namespace std;
int n,m;
int q;
struct node{
int k,index,ans;
}qu[maxn];
bool cmp1(node a,node b){
return a.k>b.k;
}
bool cmp2(node a,node b){
return a.index<b.index;
}
void input(){
scanf("%d%d",&n,&m);
scanf("%d",&q);
int i;
for(i=1;i<=q;i++){
scanf("%d",&qu[i].k);
qu[i].index=i;
}
sort(qu+1,qu+1+q,cmp1);
}
void solve(){
queue <int>que;
for(int i=n;i>=1;--i){
if(!que.empty()){
for(int j=1;j<=m;j++){
int tmp=que.front();
que.pop();
que.push(tmp);
}
}
que.push(i);
}
int cnt=1;
for(int i=n;i>=1;i--){
int tmp=que.front();
que.pop();
if(i==qu[cnt].k)
qu[cnt++].ans=tmp;
if(cnt>q)
break;
}
sort(qu+1,qu+1+q,cmp2);
for(int i=1;i<=q;i++){
printf("%d\n",qu[i].ans);
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
input();
solve();
}
} G Pangu Separates Heaven and Earth
题目链接
签到题
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
if (n == 1) { puts("18000"); }
else puts("0");
}
} H The Nth Item
题目链接
题意:对于给出第1项的查询q1得到答案a1=F[q1]。下一次的查询是q2=q1^a1,求第q次查询的答案。
思路:存在循环节,矩阵快速幂+记忆化map就可过。。。
正解,是推出O(1)的通项公式,快速幂求解。
#include <bits/stdc++.h>
#define maxn 10000005
typedef long long ll;
using namespace std;
const int p=998244353;
struct mat{
long long m[2][2];
}ans,res;
//矩阵结构体
mat mul(mat a,mat b)
{
mat tmp;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
tmp.m[i][j]=0;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
tmp.m[i][j]=(tmp.m[i][j]+(a.m[i][k]*b.m[k][j])%p)%p;
return tmp;
}
unordered_map<ll, ll>mp;
//矩阵乘法
void quickpow(long long n)
{
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
if(i==j)ans.m[i][j]=1;
else ans.m[i][j]=0;
}
while(n)
{
if(n&1LL)ans=mul(ans,res);
res=mul(res,res);
n=n>>1;
}
return;
}
int main(){
ll q,n;
scanf("%lld%lld",&q,&n);
ll ANS=0,a;
while(q--){
if(mp.count(n))
{
a=mp[n];
}else{
res.m[0][0]=3;
res.m[0][1]=2;
res.m[1][0]=1;
res.m[1][1]=0;
quickpow(n-1);
a=ans.m[0][0];
mp[n]=a;
}
// for(int i=0;i<2;i++){
// for(int j=0;j<2;j++)
// cout<<ans.m[i][j]<<" ";
// cout<<endl;
// }
// cout<<endl;
n=n^(a*a);
ANS=ANS^a;
}
printf("%lld\n",ANS);
}
京公网安备 11010502036488号