9.2模拟

本文作者回顾了参与编程竞赛的经历,分析了在T1-T4题目中的解题策略与得分情况。T1通过位运算求解异或和,T2应用容斥原理计算质数对,T3使用SPFA算法求最短路,T4未能优化暴力DP。作者意识到细节与优化的重要性,并决定避免使用#define long long。
摘要由CSDN通过智能技术生成

期望得分 100+30+100+30=260

实际得分 100+10+90+30=230

(因为开了define int long long导致TLE痛失30分)

做题过程:拿到题看完T1很有感觉但感觉暴力不好敲,就看T2发现T2也只会暴力,索性直接开T3,觉得就是一个spfa板子,之后开了T4,写了一个n^2的暴力dp但不会优化,就去开T1,发现T1的实质就是算为一位1的个数为奇数的方案数,30分钟切掉,最后看T2,感觉会30的暴力,本想用平衡树来维护集合的,但是我对自己的平衡树基本功并不自信于是用了小根堆优化,4个点就这样过去了

T1:

一共有n 张卡牌,每张卡牌上有一个正整数 ,每次可以从中选出 k张卡牌。一种选取方案的幸运值为这 k张卡牌上数的按位异或和。求所有选取方案的幸运值之和,对998244353取模。

题解上面陈述过了

Code

#include<bits/stdc++.h>
#define re register
#define inl inline
#define int long long
using namespace std;
int read(){
	int sum=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
	return sum*f;
}
const int mod=998244353;
const int N=1e5+10;
int n,a[N],k,ans;
int r[50],res[N],res2[50];
inl int ksm(int a,int b){
	int tmp=1;
	while(b){
		if(b&1) tmp=tmp*a%mod;
		b>>=1,a=a*a%mod;
	}
	return tmp;
}
int C(int x,int y){
	if(y>x) return 0;
	if(y==0||x==y) return 1;
	return (res[x]*ksm(res[y],mod-2)%mod)*ksm(res[x-y],mod-2)%mod;
}
signed main(){
	freopen("card.in","r",stdin);freopen("card.out","w",stdout);
	n=read(),k=read();
	for(re int i=1;i<=n;i++){
		a[i]=read();
		int x=a[i],t=0;
		while(x){
			if(x&1) r[t]++;
			x>>=1,t++;
		}
	}
	//for(re int i=0;i<=32;i++) cout<<r[i]<<" ";
	res[0]=res2[0]=1;
	for(re int i=1;i<=32;i++) res2[i]=(res2[i-1]*2)%mod;
	for(re int i=1;i<=n;i++) res[i]=(res[i-1]*i)%mod;
	for(re int i=0;i<=32;i++){
		for(re int j=1;j<=min(r[i],k);j+=2){
			ans=(ans+(C(r[i],j)*C(n-r[i],k-j)%mod)*res2[i]%mod)%mod;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

T2

 思路:容斥原理

当加入一个数时根据正难则反原理,我i们只需要计算原集合的数字个数减去不是质数对的个数,对于不是我们可以将一个数因数分解,再根据容斥即可得解

ans+=tot-cnt[p1]-cnt[p2]+cnt[p1*p2]..........发现系数为莫比乌斯函数,

Code

#include<bits/stdc++.h>
#define re register
#define inl inline
#define ll long long
using namespace std;
int read(){
	int sum=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
	return f*sum;
}
const int N=5e5+10;
bool vis[N],in[N];
int prime[N],mu[N],c[N],cnt,n,q,a[N];
ll ans=0;
vector<int> g[N];
void get(int n){
	mu[1]=1;
	for(re int i=2;i<=n;i++){
		if(!vis[i]) prime[++cnt]=i,mu[i]=-1;
		for(re int j=1;prime[j]*i<=n;j++){
			vis[prime[j]*i]=1;
			if(i%prime[j]==0) break;
			else mu[prime[j]*i]=-mu[i];
		}
	}
}
inl void init(){
	get(N-1);
	for(re int i=1;i<N;i++){
		for(re int j=i;j<N;j+=i){
			g[j].push_back(i);
		}
	}
}
int main(){
	freopen("pair.in","r",stdin);
	freopen("pair.out","w",stdout);
	init();
	n=read(),q=read();
	for(re int i=1;i<=n;i++) a[i]=read();
	while(q--){
		int id=read(),x;
		x=a[id];
		if(!in[id]){
			int num=g[x].size();
			for(re int i=0;i<num;i++){
				int u=g[x][i];
				ans+=mu[u]*c[u];
				c[u]++;
			}
		}
		else{
			int num=g[x].size();
			for(re int i=0;i<num;i++){
				int u=g[x][i];
				c[u]--;
				ans-=mu[u]*c[u];
			}
		}
		in[id]=!in[id];
		printf("%lld\n",ans);
	}
	return 0;
}

T3有两种方法,一种就是spfa,另一种是将连通块单独跑dijkstra,再用topo走最短路

Code(dijkstra+toposort)

#include<bits/stdc++.h>
#define re register
#define inl inline
#define ll long long
using namespace std;
int read(){
	int sum=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
	return f*sum;
}
const int N=5e5+10;
const int inf=2e9;
int t,y,p,s,cnt,head[N],dep,col[N],sta[N],dfn[N],low[N],vis[N],sum,top,cnt2,head2[N];
vector<int> block[N];
int dis[N],ind[N];
struct Node{
	int to,w,nxt;
}e[N<<1],r[N<<1];
inl void add(int u,int v,int w){
	e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
inl void add2(int u,int v,int w){
	r[++cnt2].to=v;r[cnt2].w=w;r[cnt2].nxt=head2[u];head2[u]=cnt2;
}
inl void tarjan(int u){
	dfn[u]=low[u]=++dep;
	sta[++top]=u;
	for(re int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
		else if(!col[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		col[u]=++sum;
		block[sum].push_back(u);
		while(sta[top]!=u){
			col[sta[top]]=sum;
			block[sum].push_back(sta[top--]);
		}
		top--;
	}
}
queue<int> h;
struct node{
	int u,d;
	bool operator <(const node &lzb) const{
		return d>lzb.d;
	}
};
priority_queue<node> q;
inl void dijkstra(){
	while(!q.empty()){
		node tmp=q.top();q.pop();
		int u=tmp.u;
		if(vis[u]) continue;
		vis[u]=1;
		for(re int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			if(dis[u]<inf&&dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				q.push((node){v,dis[v]});
			}
		}
		for(re int i=head2[u];i;i=r[i].nxt){
			int v=r[i].to;
			if(dis[u]<inf&&dis[v]>dis[u]+r[i].w){
				dis[v]=dis[u]+r[i].w;
			}
			ind[col[v]]--;
			if(!ind[col[v]]) h.push(col[v]);
		}
	}
}
inl void topsort(int u){
	for(re int i=1;i<=t;i++) dis[i]=2e9;
	for(re int i=1;i<=sum;i++){
		if(!ind[i]) h.push(i);
	}
	dis[u]=0;
	while(!h.empty()){
		int tmp=h.front();h.pop();
		for(re int i=0;i<block[tmp].size();i++){
			int v=block[tmp][i];
			q.push((node){v,dis[v]});
		}
		dijkstra();
	}
}
signed main(){
	freopen("roadplane.in","r",stdin);
	freopen("roadplane.out","w",stdout);
	t=read(),y=read(),p=read(),s=read();
	for(re int i=1;i<=y;i++){
		int u=read(),v=read(),w=read();
		add(u,v,w);add(v,u,w);
	}
	for(re int i=1;i<=t;i++){
		if(!dfn[i]) tarjan(i);
	}
	for(re int i=1;i<=p;i++){
		int u=read(),v=read(),w=read();
		add2(u,v,w);
		if(col[u]!=col[v]) ind[col[v]]++;
	}
	topsort(s);
	for(re int i=1;i<=t;i++){
		if(dis[i]==2e9) puts("NO PATH");
		else printf("%d\n",dis[i]);
	}
	return 0;
}

T4;就会暴力的30~

总结:以后就不开define long long了(,dp优化与数论还需要多练练,但要更注意细节问题,争取日后不挂分!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值