QLU校赛

as a tester,problems are good and I recommend participating

验题是几周前的事情了,只能凭借印象口胡两下

B.新大陆

暴力,复杂度O(n*m)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
using ll=long long;
vector<ll>g[N];
vector<int>st[N];

bool check(int p1,int p2,int &h,int &w)
{
    for(int i=p1;i<=p1+h-1;++i)
    {
        for(int j=p2;j<=p2+w-1;++j)
        {
            if(g[i][j]!=g[p1][p2])return false;
            st[i][j]=1;
        }
    }
    return true;
}
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)g[i].resize(m+1),st[i].resize(m+1);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)scanf("%lld",&g[i][j]);
    int h,w;
    scanf("%d%d",&h,&w);
  
    
    
    for(int i=1;i<=n-h+1;++i)
    for(int j=1;j<=m-w+1;++j)
    {
        if(st[i][j])continue;
        if(check(i,j,h,w))
        {
            printf("YES\n");return 0;
        }
    }
    for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)st[i][j]=0;
    for(int i=1;i<=n-w+1;++i)
    for(int j=1;j<=m-h+1;++j)
    {
        if(st[i][j])continue;
        if(check(i,j,w,h))
        {
            printf("YES\n");return 0;
        }
    }
    printf("NO\n");return 0;
}

C

勇者之塔,考虑下边界

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

int main()
{
    ll n,m;cin>>n>>m;
    int T;scanf("%d",&T);
    while(T--)
    {
        int x,y,k;scanf("%d%d%d",&x,&y,&k);
        if(!x&&!y){printf("1 1 1\n");continue ;}
        int t=min((x>0?((n+x-1)/x):0x3f3f3f3f),
        (y>0?((m+y-1)/y):0x3f3f3f3f));
        int rs1=1+k/t;
        k=k%t;
        int rs2=x*k+1,rs3=y*k+1;
        printf("%d %d %d\n",rs1,rs2,rs3);
        
    }
}

D  史莱姆

发现n*m<1e6考虑n<1e3或者m<1e3

所以有1e3个优先队列

复杂度 O(min(n,m)*p*log(m));大概这样?忘了

不过有去掉log的更优解,当然,写线段树也是很好想的东西

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
using ll=long long;
vector<vector<pair<int,int>>> e[N];
vector<int>w[N];
int aa,bb;
int col[N];
int f(int i)
{
    return col[i]*aa+bb;
}
// if n<=m
void solve1(int n,int m,int p,int c)
{
    for(int i=1;i<=n;++i)e[i].resize(m+1),w[i].resize(m+1);
    for(int i=1;i<=c;++i)scanf("%d",&col[i]);
    unordered_map<int,int> mp;
    for(int i=1;i<=c;++i)mp[f(i)]=i;
    mp[0]=0;
    while(p--)
    {
        int x1,y1,x2,y2,c1;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c1);
        for(int i=x1;i<=x2;++i)
        e[i][y1].push_back({f(c1),y2});
    }
    for(int i=1;i<=n;++i)
    {
        priority_queue<pair<int,int>> heap;
        for(int j=1;j<=m;++j)
        {
            for(auto v:e[i][j])
            heap.push(v);
            while((int)heap.size()&&heap.top().second<j)heap.pop();
            if((int)heap.size())
            w[i][j]=mp[max(heap.top().first,0)];
        }
    }
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    printf("%d%c",w[i][j]," \n"[j==m]);
}

void solve2(int n,int m,int p,int c)
{
    for(int i=1;i<=m;++i)e[i].resize(n+1),w[i].resize(n+1);
    for(int i=1;i<=c;++i)scanf("%d",&col[i]);
    unordered_map<int,int> mp;
    for(int i=1;i<=c;++i)mp[f(i)]=i;
    mp[0]=0;
    while(p--)
    {
        int x1,y1,x2,y2,c1;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c1);
        for(int i=y1;i<=y2;++i)
        e[i][x1].push_back({f(c1),x2});
    }
    
    for(int i=1;i<=m;++i)
    {
        priority_queue<pair<int,int>> heap;
        for(int j=1;j<=n;++j)
        {
            for(auto v:e[i][j])
            heap.push(v);
            while((int)heap.size()&&heap.top().second<j)heap.pop();
            if((int)heap.size())
            w[i][j]=mp[max(heap.top().first,0)];
        }
    }
    for(int i=1;i<=n;++i)
    for(int j=1;j<=m;++j)
    printf("%d%c",w[j][i]," \n"[j==m]); 
}
int main()
{
    int n,m,p,c;scanf("%d%d%d%d%d%d",&n,&m,&p,&c,&aa,&bb);
    if(n<=m)solve1(n,m,p,c);
    else solve2(n,m,p,c);
}

E 贴贴

考虑到质数是稠密的,并且平均log个数就有一个,所以平均会在log内求的所需值,上下边界求一下取min

#include<bits/stdc++.h>
using namespace std;
const int P=998244353;
using ll=long long;
const int N=1e7+10;
int pri[N],cnt;
bool st[N];
void init()
{
    for(int i=2;i<N;++i)
    {
        if(!st[i])pri[++cnt]=i;
        for(int j=1;pri[j]*i<N;++j)
        {
            st[pri[j]*i]=1;
            if(i%pri[j]==0)break;
        }
    }
}
bool check(ll n)
{
    for(int i=1;i<=cnt;++i)
    {
        if(n==1)break;
        if(n%pri[i]==0)
        {
            if(n%(1ll*pri[i]*pri[i])==0)return 0;
            n/=pri[i];
            //cout<<"ss "<<pri[i]<<endl;
        }
    }
    return 1;
}
ll up(ll n)
{
    while(n)if(!check(n))++n;else return n;
}
ll down(ll n)
{
    while(n)if(!check(n))--n;else return n;
}
int main()
{
    init();
    ll n;cin>>n;
    ll rs_up=up(n);
    ll rs_down=down(n);
    if(rs_down==rs_up){cout<<n<<endl;return 0;}
    if(n-rs_down<=rs_up-n)
    cout<<rs_down<<'\n';
    
    if(n-rs_down>=rs_up-n)
    cout<<rs_up<<endl;
}

F 时间就是金钱

虚树,队友说很板?但我不会

#include <iostream> /// 洛谷 4103 每次询问点集合中各点之间 1.路径长度总和 2.最短路径长度 3.最长路径长度
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int N=100005;
struct pp
{
	int to;
	int old;
}edge[N*2];
int newly[N],cnt;
int dep[N],lg[N],f[N][25],dfn[N],dfn_cnt;
int ss[N],top,flag[N];
vector<pair<int, int> >a;
int vvv[N];
long long down[N],dp[N],ans;
int sz[N];

void add(int u, int v)
{
	edge[cnt]={v, newly[u]};
	newly[u]=cnt++;
}

void dfs(int x, int fa)
{
	dfn[x]=++dfn_cnt;
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	for(int i=1; i<=lg[dep[x]]; i++)
		f[x][i]=f[f[x][i-1]][i-1];
	for(int i=newly[x]; ~i; i=edge[i].old)
		if(edge[i].to!=fa)
			dfs(edge[i].to, x);
}

int lca(int x, int y)
{
	if(dep[x]<dep[y])
		swap(x, y);
	while(dep[x]>dep[y])
		x=f[x][lg[dep[x]-dep[y]]-1];
	if(x==y) return x;
	for(int k=lg[dep[x]]-1; k>=0; k--)
		if(f[x][k]!=f[y][k])
			x=f[x][k],y=f[y][k];
	return f[x][0];
}

void down_dfs(int x, int fa)
{
//	cout << x << '\n';
	sz[x]=vvv[x];
	for(int i=newly[x]; ~i; i=edge[i].old)
	{
		int son=edge[i].to,w=dep[son]-dep[x];
		if(son==fa)
			continue;
		down_dfs(son, x);
		sz[x]+=sz[son];
		down[x]+=down[son]+1ll*w*sz[son];
	}
}

void ans_dfs(int x, int fa)
{
	ans=min(ans, dp[x]);
	for(int i=newly[x]; ~i; i=edge[i].old)
	{
		int son=edge[i].to,w=dep[son]-dep[x];
		if(son==fa)
			continue;
		dp[son]=dp[x]-down[son]-1ll*w*sz[son]+1ll*(sz[1]-sz[son])*w+down[son];
		ans_dfs(son, x);
	}
}

void init_dfs(int x, int fa)
{
	for(int i=newly[x]; ~i; i=edge[i].old)
	{
		if(edge[i].to==fa)
			continue;
		init_dfs(edge[i].to, x);
	}
	newly[x]=-1,flag[x]=0,dp[x]=0,down[x]=0,sz[x]=0,vvv[x]=0;
}

int main()
{
	int n,q;
	memset(newly,-1,sizeof(newly));
	scanf("%d%d", &n, &q);
	for(int i=1; i<=n; i++)
		lg[i]=lg[i>>1]+1;
	for(int i=1; i<n; i++)
	{
		int x,y;
		scanf("%d%d", &x, &y);
		add(x, y),add(y, x);
	}
	dfs(1, 0);
	memset(newly,-1,sizeof(newly));
//	cout << "------" << '\n';
	while(q--)
	{
		int m; scanf("%d", &m);
		a.clear(),top=cnt=0;
		int k; scanf("%d", &k);
		for(int i=1; i<=k; i++)
		{
			int x; scanf("%d", &x);
			vvv[x]++;
			if(flag[x])
				continue;
			flag[x]=1;
			a.push_back({dfn[x], x});
		}
		int cc=1; // 默认根节点入栈
		if(!flag[cc])
			a.push_back({dfn[cc], cc});
		sort(a.begin(), a.end());
		ss[++top]=cc;
		for(int i=1; i<a.size(); i++)
		{
			int now=a[i].second;
			if(top==1)
				ss[++top]=now;
			else
			{
				int p=lca(now, ss[top]);
				if(p==ss[top])
					ss[++top]=now;
				else
				{
					while(top>1 && dfn[p]<=dfn[ss[top-1]])
						add(ss[top-1], ss[top]),top--;
					if(p!=ss[top])
						add(p, ss[top]),ss[top]=p;
					ss[++top]=now;
				}
			}
		}
		while(top>1)
			add(ss[top-1], ss[top]),top--;
		ans=m;
		down_dfs(cc, -1);
		dp[cc]=down[cc];
		ans_dfs(cc, -1);
//		cout << " size : " << a.size() << '\n';
//		for(int i=0; i<a.size(); i++)
//			if(flag[a[i].second])
//				cout << a[i].second << " : " << dp[a[i].second] << "  ---- ";
//		cout << '\n';
		if(ans==m)
			cout << "Good game" << '\n';
		else
			cout << ans << '\n';
		init_dfs(cc, -1);
	}
	return 0;
}

G 简单的数学

很容易发现化简后就是n

#include<bits/stdc++.h>
using namespace std;
const int P=998244353;
using ll=long long;

int main()
{
    int n;cin>>n;
    cout<<n<<endl;
}

H L的子序列

很一眼的树状数组维护DP

#include<bits/stdc++.h>
using namespace std;
const int P=1e9+7;
using ll=long long;
const int N=1e5+10;
template<typename T> struct BIT
{
    ll tr[N];
    T query(int x){T res=0;for(;x;x-=x&-x)res+=tr[x];return res;}
    void modify(int x,T y){for(;x<N;x+=x&-x)tr[x]+=y;}
    T cal(int l,int r){return query(r)-query(l-1);}
};
using Bit=BIT<ll>;

ll dp[N],f[N];
Bit bit_dp,bit_f;
void add(ll &a,ll b)
{
    a+=b;if(a>=P)a-=P;
}
int main()
{
    int n;scanf("%d",&n);
    vector<ll> a(n+1);
    for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
    vector<ll> b(n);
    for(int i=1;i<=n;++i)b[i-1]=a[i];
    sort(b.begin(),b.end());
    
    map<ll,int> mp;
    mp[-1]=0;
    int cnt=0;
    for(int i=1;i<=n;++i)if(mp.find(b[i-1])==mp.end())
    mp[b[i-1]]=++cnt;;
    
    for(int i=1;i<=n;++i)
    {
        ll t=a[i]/2;
        ll pos=mp[a[i]];
        add(dp[i],1);add(f[i],1);
        auto p1=mp.upper_bound(t);
        --p1;
        // if(p1!=mp.begin())
        // {
            add(dp[i],bit_dp.query(p1->second)%P);
            // cout<<"now is p1: "<<(p1->second)<<endl;
            // cout<<"i--> "<<i<<" dp[i]-->"<<dp[i]<<endl;
            add(f[i],(bit_f.query(p1->second))%P);
            bit_dp.modify(pos,dp[i]);
            bit_f.modify(pos,(f[i]+dp[i])%P);
        // }
    }
    ll rs=0;
    // for(int i=1;i<=n;++i)printf("%lld%c",dp[i]," \n"[i==n]);
    // for(int i=1;i<=n;++i)printf("%lld%c",f[i]," \n"[i==n]);
    for(int i=1;i<=n;++i)add(rs,f[i]);
    cout<<rs<<endl;
}

I 秋游

感觉以前写过吧,做几遍dijkstra之后状压

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e5+10;
using pli=pair<ll,int>;
using pii=pair<int,int>;
vector<pii> e[N];
ll dist[N];
ll dis[30][30];
ll dp[1<<20][20];
void dijkstra(int root)
{
    memset(dist,0x3f,sizeof(dist));
    dist[root]=0;
    priority_queue<pli,vector<pli>,greater<pli>>heap;
    heap.push({0,root});
    while(heap.size())
    {
        auto [val,u]=heap.top();heap.pop();
        for(auto [v,w]:e[u])
        {
            if(dist[v]>dist[u]+w)
            {
                dist[v]=dist[u]+w;
                heap.push({dist[v],v});
            }
        }
    }
}
int main()
{
    int n,x,y;scanf("%d%d%d",&n,&x,&y);
    vector<int>spots(x);
    for(auto &v:spots)cin>>v;
    int m;scanf("%d",&m);
    for(int i=1,u,v,w;i<=m;++i)
    scanf("%d%d%d",&u,&v,&w),e[u].push_back({v,w}),e[v].push_back({u,w});
    
    dijkstra(1);
    for(int i=1;i<=x;++i)
    dis[0][i]=dist[spots[i-1]];
    for(int i=1;i<=x;++i)
    {
        dijkstra(spots[i-1]);
        for(int j=1;j<=x;++j)
        dis[i][j]=dist[spots[j-1]];
        dis[i][0]=dist[1];
    }
    memset(dp,0x3f,sizeof(dp));
    dp[1][0]=0;
    for(int i=1;i<1<<x+1;++i)
    {
        
        for(int j=0;j<=x;++j)
        {
            if(i&1<<j)
            for(int k=0;k<=x;++k)
            {

                dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+dis[j][k]);
            }
        }
    }
    ll rs=1e18;
    for(int i=0;i<1<<x+1;++i)
    {
        if(__builtin_popcount(i)!=y+1)continue;
        for(int j=0;j<=x;++j)
        rs=min(rs,dp[i][j]+dis[j][0]);
    }
    //cout<<dis[2][1]<<'\n';
    cout<<rs<<'\n';
}

J 串串大师

队友写的,不予评价



void init()
{
	last=0;
	len[1]=-1;
	s[0]='?';
	fail[0]=fail[1]=1;
}

int get_fail(int x)
{
	while(s[ni-len[x]-1]!=s[ni])
		x=fail[x];
	return x;
}

void add(int c, int idx)
{
	int old=get_fail(last);  
	if(!pam[old][c]) // 
	{
		int now=++pam_cnt;
		fail[now]=pam[get_fail(fail[old])][c];
		pam[old][c]=now;
		len[now]=len[old]+2;
		for(int j=0; j<26; j++)
			mm_cnt[now][j]=mm_cnt[old][j];
		mm_cnt[now][c]++;
		if(len[now]!=1)
			mm_cnt[now][c]++;
	}
	last=pam[old][c];
	cnt[last]++;
}

void count() 
{
	for(int i=pam_cnt; i>=2; i--)
		(cnt[fail[i]]+=cnt[i])%=mod;
}


signed main()
{
	pam_cnt=1;
	int k,n;
	scanf("%lld", &k);
	for(int i=1; i<=k; i++)
	{
		scanf("%s", s+1);init();
		n=strlen(s+1);
		for(ni=1; ni<=n; ni++)
			add(s[ni]-'a', i);
	}
	count();
	long long ans=0;
	for(int i=2; i<=pam_cnt; i++)
	{
		long long res=1;
		for(int j=0; j<26; j++)
			if(mm_cnt[i][j])
				res=res*mm_cnt[i][j]%mod;
//		cout << len[i] << " : " << res << '\n';
		
		ans=(ans+res*cnt[i]%mod)%mod;
	}
	cout << ans << '\n';
	return 0;
}

K L的树

队友写的,不予评价

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=100005;
struct seg_tree
{
	int tree[N<<2];
	void push_up(int p)
	{
		tree[p]=tree[p<<1]+tree[p<<1|1];
	}
	void modify(int p, int tl, int tr, int dis, int v)
	{
		if(tl==tr)
		{
			tree[p]+=v;
			return ;
		}
		int mid=(tl+tr)>>1;
		if(dis<=mid)
			modify(p<<1, tl, mid, dis, v);
		else
			modify(p<<1|1, mid+1, tr, dis, v);
		push_up(p);
	}
	int query(int p, int l, int r, int dl, int dr)
	{
		if(l>=dl && r<=dr) // 被目标区间包含 立即返回答案
			return tree[p];
		int mid=(l+r)>>1;
		int ans=0;
		if(dl<=mid)
			ans+=query(p<<1, l, mid, dl, dr);
		if(dr>mid)
			ans+=query(p<<1|1, mid+1, r, dl, dr);
		return ans;
	}
}T[11];
struct pp
{
	int to;
	int old;
}edge[N<<1];
int newly[N],cnt;
int dfn[N],out[N],dfn_cnt;
int now[N];
void add(int u, int v)
{
	edge[cnt]={v, newly[u]};
	newly[u]=cnt++;
}

void dfs(int x, int fa)
{
	dfn[x]=++dfn_cnt;
	for(int i=newly[x]; ~i; i=edge[i].old)
	{
		int to=edge[i].to;
		if(to==fa)
			continue;
		dfs(to, x);
	}
	out[x]=dfn_cnt;
}
int uu[N],ans[20];
bool cmp(int x, int y)
{
	return dfn[x]<dfn[y];
}

int main()
{
	memset(newly,-1,sizeof(newly));
	int n,q; scanf("%d%d", &n, &q);
	for(int i=1; i<n; i++)
	{
		int u,v;
		scanf("%d%d", &u, &v);
		add(u, v),add(v, u);
	}
	dfs(1, -1);
	for(int i=1; i<=n; i++)
	{
		int c; scanf("%d", &c);
		now[i]=c;
		T[c].modify(1, 1, dfn_cnt, dfn[i], 1);
	}
//	for(int i=1; i<=n; i++)
//		cout << dfn[i] << ' ';
//	cout << '\n';
//	cout << T[1].query(1, 1, dfn_cnt, dfn[2], out[2]) << '\n';
	while(q--)
	{
		int op; scanf("%d", &op);
		if(op==1)
		{
			int x,y; scanf("%d%d", &x, &y);
			T[now[x]].modify(1, 1, dfn_cnt, dfn[x], -1);
			T[y].modify(1, 1, dfn_cnt, dfn[x], 1);
			now[x]=y;
		}
		else
		{
			for(int i=1; i<=10; i++)
				ans[i]=0;
			int m; scanf("%d", &m);
			for(int i=1; i<=m; i++)
				scanf("%d", &uu[i]);
			sort(uu+1, uu+1+m, cmp);
//			cout << "排序后为 : ";
//			for(int i=1; i<=m; i++)
//				cout << uu[i] << ' ';
//			cout << '\n';
			int pre=-1;
			for(int i=1; i<=m; i++)
			{
				if(dfn[uu[i]]<=pre)
					continue;
				pre=out[uu[i]];
				for(int j=1; j<=10; j++)
					ans[j]+=T[j].query(1, 1, dfn_cnt, dfn[uu[i]], out[uu[i]]);
			}
			for(int i=1; i<=10; i++)
				cout << ans[i] << " \n"[i==10];
		}
	}
	return 0;
}

K 奥特曼的时间管理

写模拟一点也不拿手啊,感觉得加把油了

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using pll=pair<ll,ll>;
ll x,y,z;
ll get(char a, char b)
{
    return (a-'0')*10+b-'0';
}
ll cal(ll a,ll b,ll c)
{
    // ll tmp=c/z;
    // c%=z;
    // b+=tmp;
    // tmp=b/y;b%=y;a+=tmp;
    return a*y*z+b*z+c;
}
int main()
{
    ll n,k,val;
    cin>>n>>x>>y>>z>>k>>val;
    vector<pll> q;
    for(int i=1;i<=n;++i)
    {
        string str;
        cin>>str;
        ll t1=cal(get(str[0],str[1]),
        get(str[3],str[4]),get(str[6],str[7]));
        cin>>str;
        ll t2=cal(get(str[0],str[1]),
        get(str[3],str[4]),get(str[6],str[7]));
        q.push_back({t1,t2});
       // cout<<t1<<" "<<t2<<endl;
    }
    sort(q.begin(),q.end());
    ll rs=0,lst=q[0].first-1;
    ll N=cal(x-1,y-1,z-1);
    for(auto [S,T]:q)
    {
        if(T>N)T=N;
        if(T<lst)continue;
        
        if(S<=lst&&T>lst)
        {
            rs+=T-lst;
            lst=T;
        }
        else if(S>=lst&&S<=lst+k)
        {
            rs+=T-lst;
            lst=T;
        }
        else if(S>lst+k)
        {
            rs+=T-S+1+k;
            lst=T;
            // cout<<S<<" "<<T<<" "<<rs<<endl;
        }
    }
    rs+=min(k,N-lst);
    cout<<rs*val<<endl;
    // cout<<(4793-4733+4733-4710+1)*2;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值