solve : 3/10

补题 : 5/10


https://www.jisuanke.com/contest/3870?view=challenges

B. Fire-Fighting Hero

大概就是跑两个最短路,然后由于出题人的**英语,*****

#include<bits/stdc++.h>
using namespace std;
const int MAX = 2e6+5;
const int MAXN = 1e3+5;
const int INF = 0x3f3f3f3f;
int n,m,s,k,c,first[MAXN],nextt[MAX],u[MAX],v[MAX],w[MAX],cnt=0;
int dd[MAXN],dis[MAXN],num1,num2;
int book[MAXN][MAXN];
bool vis[MAXN];
struct point{
	int dot,length;
};
bool operator<(point a,point b){
	return a.length>b.length;
}
void add(int a,int b,int c){
	u[cnt]=a,v[cnt]=b,w[cnt]=c;
	nextt[cnt]=first[u[cnt]];
	first[u[cnt]]=cnt;++cnt;
}
void dijkstra(int start,int op){
	priority_queue<point> list1;
	for(int i=1;i<=n;++i) vis[i]=false,dis[i]=INF;
	if(op==0){
		dis[start]=0;
		list1.push({start,dis[start]});
	}
	else{
		for(int i=1;i<=k;++i){
			dis[dd[i]]=0;
			list1.push({dd[i],dis[dd[i]]});
		}
	}
	while(!list1.empty()){
		point now = list1.top();
		list1.pop();
		if(vis[now.dot]) continue;
		vis[now.dot]=true;
		for(int num = first[now.dot];num!=-1;num=nextt[num]){
			if(dis[v[num]]>dis[u[num]]+w[num]){
				dis[v[num]]=dis[u[num]]+w[num];
				list1.push({v[num],dis[v[num]]});
			}
		}
	}
	if(op==0)
		for(int i=1;i<=n;++i)
			num1 = max(num1,dis[i]);
	else
		for(int i=1;i<=n;++i)
			num2 = max(num2,dis[i]);
}
void solve(){
	int t;
	scanf("%d",&t);
	while(t--){
		cnt=0,num1=0,num2=0;
		scanf("%d%d%d%d%d",&n,&m,&s,&k,&c);
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				book[i][j]=INF;
		for(int i=1;i<=n;++i) first[i]=-1;
		for(int i=1;i<=k;++i) scanf("%d",&dd[i]);
		for(int i=1;i<=m;++i){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			book[a][b]=min(book[a][b],c);
			book[b][a]=min(book[b][a],c);
		}
		for(int i=1;i<=n;++i){
			for(int j=i+1;j<=n;++j){
				if(book[i][j]!=INF){
					add(i,j,book[i][j]);
					add(j,i,book[i][j]);
				}
			}
		}
		dijkstra(s,0);
		dijkstra(dd[1],1);
		if(num1<=num2*c) printf("%d\n",num1);
		else printf("%d\n",num2);
	}
}
int main(void)
{
	solve();
	return 0;
}

 C. Hello 2019

人均打爆 tourist 的题。

让一个串的一段(子串)只包含2019不包含2018删除最少的字符数量。

考虑使用矩阵来维护每一个位置/子串的状态,

0 -> 

1 -> 2

2 -> 20

3 -> 201

4 -> 2019

4 -> 2018

合并两个状态的时候,考虑将两个矩阵合成一个矩阵,考虑类似于floyd的三层循环来解决。

这样我们就可以在 n 的时间内求出一个询问,总时间复杂度是 n*q ,显然会超时。

于是考虑用线段树维护,只需要 logn 的时间就可以求出这一段区间的贡献,总复杂度 qlogn

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
#define lson left,mid,k<<1
#define rson mid+1,right,k<<1|1
#define imid int mid=(left+right)>>1;
using namespace std;
const int MAXN = 2e5 + 5;
const ll inf = 2e5 + 10;
struct Martix
{
	int jzk[5][5];
	void zero()
	{
		memset(jzk, 0, sizeof(jzk));
	}
	void one()
	{
		zero();
		for (int i = 0; i < 5; i++)
			jzk[i][i] = 1;
	}
	void MAX()
	{
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				jzk[i][j] = inf;
	}
};
Martix operator * (Martix a, Martix b)
{
	Martix ans;
	ans.MAX();
	for (int i = 0; i < 5; i++)
		for (int j = 0; j < 5; j++)
			for (int k = 0; k < 5; k++)
				ans.jzk[i][j] = min(ans.jzk[i][j], a.jzk[i][k] + b.jzk[k][j]);
	return ans;
}
struct node
{
	int l;
	int r;
	Martix a;
}que[MAXN * 4];
int n, q, ql, qr;
char s[200005], s1[200005];
void up(int k)
{
	que[k].a = que[k << 1].a * que[k << 1 | 1].a;
}
void build(int left = 1, int right = n, int k = 1)
{
	que[k].l = left;
	que[k].r = right;
	if (left == right)
	{
		que[k].a.MAX();
		for (int i = 0; i < 5; i++)
			que[k].a.jzk[i][i] = 0;
		if (s[left] == '2')
			que[k].a.jzk[0][0] = 1, que[k].a.jzk[0][1] = 0;
		else if (s[left] == '0')
			que[k].a.jzk[1][1] = 1, que[k].a.jzk[1][2] = 0;
		else if (s[left] == '1')
			que[k].a.jzk[2][2] = 1, que[k].a.jzk[2][3] = 0;
		else if (s[left] == '9')
			que[k].a.jzk[3][3] = 1, que[k].a.jzk[3][4] = 0;
		else if (s[left] == '8')
			que[k].a.jzk[3][3] = 1, que[k].a.jzk[4][4] = 1;
		return;
	}
	imid;
	build(lson);
	build(rson);
	up(k);
}
Martix query(int left = 1, int right = n, int k = 1)
{
	if (ql <= left && right <= qr)
		return que[k].a;
	imid;
	if (qr <= mid)
		return query(lson);
	else if (ql > mid)
		return query(rson);
	else
		return query(lson) * query(rson);
}
int main()
{
	sc("%d%d", &n, &q);
	sc("%s", s1 + 1);
	for (int i = n; i >= 1; i--)
		s[i] = s1[n - i + 1];
	build();
	while (q--)
	{
		sc("%d%d", &ql, &qr);
		ql = n - ql + 1;
		qr = n - qr + 1;
		swap(ql, qr);
		Martix ans = query();
		ll res = ans.jzk[0][4];
		if (res >= inf)
			pr("-1\n");
		else
			pr("%lld\n", res);
	}
}

 E. Magic Master

出题人麻烦出现解释一下为什么 Tnm=4e9,能在6s跑完

暴力跑约瑟夫环

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
#define lson left,mid,k<<1
#define rson mid+1,right,k<<1|1
#define imid int mid=(left+right)>>1;
using namespace std;
int ans[40000005];
int in[105];
int main()
{
	int T;
	sc("%d", &T);
	while (T--)
	{
		int n, m, q, maxn = 0;
		sc("%d%d%d", &n, &m, &q);
		for (int i = 0; i < q; i++)
		{
			sc("%d", &in[i]);
			maxn = max(maxn, in[i]);
		}
		deque<int>deq;
		for (int i = 1; i <= n; i++)
			deq.push_back(i);
		for (int i = 1; i <= n; i++)
		{
			ans[deq.front()] = i;
			deq.pop_front();
			if (i > maxn)
				break;
            int tt=m%deq.size();
			for (int j = 0; j < tt; j++)
			{
				int t = deq.front();
				deq.pop_front();
				deq.push_back(t);
			}
		}
		for (int i = 0; i < q; i++)
			pr("%d\n", ans[in[i]]);
	}
}

 H. The Nth Item

群老哥说这种一个数*一个数字的平方,这种生成器,是有循环节的,而且还比较小,所以矩阵乘法跑1e7次+记忆化搜索是不会T的,实测。

其实正解应该是分块吧。

将一个大整数分为3个六块,预处理每一块的答案,然后乘一下就是最终答案。

记忆化:

正确通过 2019-09-08 21:26 315ms 1624kB c++
#include <bits/stdc++.h>
#define sc scanf
#define pr printf
#define ll long long
using namespace std;
const ll mod = 998244353;
map<ll, ll>mp;
struct node
{
	ll a[2][2];
	void zero()
	{
		memset(a, 0, sizeof(a));
	}
	void one()
	{
		zero();
		a[0][0] = a[1][1] = 1;
	}
	void pre()
	{
		a[0][0] = 1;
		a[1][0] = 0;
		a[0][1] = 0;
		a[1][1] = 0;
	}
	void temp()
	{
		a[0][0] = 3;
		a[0][1] = 2;
		a[1][0] = 1;
		a[1][1] = 0;
	}
	node operator * (node other)
	{
		node ans;
		ans.zero();
		for (int i = 0; i < 2; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				for (int k = 0; k < 2; k++)
				{
					ans.a[i][j] += a[i][k] * other.a[k][j];
					ans.a[i][j] %= mod;
				}
			}
		}
		return ans;
	}
};
ll qqq[4];
node power(node a, ll b)
{
	node res;
	res.one();
	while (b)
	{
		if (b & 1)
			res = res * a;
		a = a * a;
		b >>= 1;
	}
	return res;
}
node qwe[61];
ll get(ll n)
{
	n++;
	if (n == 0)
		return 0;
	if (n == 1)
		return 1;
	node t;
	t.temp();
	node a;
	a.pre();
	node ans;
	ans.one();
	ll num = n - 2;
	for (int i = 0; i <= 60; i++)
	{
		if ((1LL << i) & num)
			ans = ans * qwe[i];
	}
	ans = ans * a;
	return ans.a[0][0];
}
int main()
{
	node t;
	t.temp();
	qwe[0].temp();
	for (int i = 1; i <= 60; i++)
	{
		qwe[i] = power(t, 1LL << i);
	}
	ll q, n;
	sc("%lld%lld", &q, &n);
	ll ans = 0;
	while (q--)
	{/*
		sc("%lld", &n);
		ll re = get(n);
		pr("%lld\n", re);*/
		ll res = 0;
		if (mp.count(n) == 0)
		{
			res = get(n);
			mp[n] = res;
		}
		else
			res = mp[n];
		ans ^= res;
		n = (n ^ (res * res));
		//pr("%lld\n", n);
	}
	pr("%lld\n", ans);
}
//90353790

分块:

正确通过 2019-09-10 19:14 799ms 125352kB c++
#include <bits/stdc++.h>
#define sc scanf
#define pr printf
#define ll long long
using namespace std;
const ll mod = 998244353;
map<ll, ll>mp;
struct node
{
	ll a[2][2];
	void zero()
	{
		memset(a, 0, sizeof(a));
	}
	void one()
	{
		zero();
		a[0][0] = a[1][1] = 1;
	}
	void pre()
	{
		a[0][0] = 1;
		a[1][0] = 0;
		a[0][1] = 0;
		a[1][1] = 0;
	}
	void temp()
	{
		a[0][0] = 3;
		a[0][1] = 2;
		a[1][0] = 1;
		a[1][1] = 0;
	}
	node operator * (node other)
	{
		node ans;
		ans.zero();
		for (int i = 0; i < 2; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				for (int k = 0; k < 2; k++)
				{
					ans.a[i][j] += a[i][k] * other.a[k][j];
					ans.a[i][j] %= mod;
				}
			}
		}
		return ans;
	}
};
ll qqq[4];
node power(node a, ll b)
{
	node res;
	res.one();
	while (b)
	{
		if (b & 1)
			res = res * a;
		a = a * a;
		b >>= 1;
	}
	return res;
}
node qwe[4][1000005];
ll get(ll n)
{
	n++;
	if (n == 0)
		return 0;
	if (n == 1)
		return 1;
	node t;
	t.temp();
	node a;
	a.pre();
	node ans;
	ans.one();
	ll num = n - 2;
	ans = qwe[0][num % 1000000] * qwe[1][(num / 1000000) % 1000000] * qwe[2][(n / 1000000000000) % 1000000] * qwe[3][(n / 1000000000000000000) % 1000000];
	ans = ans * a;
	return ans.a[0][0];
}
void init()
{
	node t;
	t.temp();
	qwe[0][0].one();
	qwe[1][0].one();
	qwe[2][0].one();
	qwe[3][0].one();
	for (int i = 1; i <= 1000000; i++)
		qwe[0][i] = qwe[0][i - 1] * t;
	for (int i = 1; i <= 1000000; i++)
		qwe[1][i] = qwe[1][i - 1] * qwe[0][1000000];
	for (int i = 1; i <= 1000000; i++)
		qwe[2][i] = qwe[2][i - 1] * qwe[1][1000000];
	for (int i = 1; i <= 10; i++)
		qwe[3][i] = qwe[3][i - 1] * qwe[2][1000000];
}
int main()
{
	init();
	ll q, n;
	sc("%lld%lld", &q, &n);
	ll ans = 0;
	while (q--)
	{
		ll res = 0;
		res = get(n);
		ans ^= res;
		n = (n ^ (res * res));
		//pr("%lld\n", n);
	}
	pr("%lld\n", ans);
}
//90353790