2021年第二届辽宁省程序设计竞赛游玩总结

2021年第二届辽宁省程序设计竞赛游玩总结:

1.比赛体验

从某方面感觉比去年差多了,不知道为什么不能有题面了。

中午也不能有志愿者送盒饭。这三人一机属实难顶。

题目质量感觉还不错,感觉用作省赛恰到好处。

中文题面好评。

2.比赛过程

热身赛略,大家不到1个小时都AK了,感觉非常热身

话说最后一题撞了L大佬出过的原题?

暴露了做题量过少的问题

比赛开始。

开局七个题签的非常顺利,甚至一度rank 2

然后拉垮了,没有跟榜对象感觉还是不太熟悉

开了两个不可做的题,当时A觉得“数据完全随机”似乎有乱搞的可能,看了半天也没看明白。和一个K,想了一个小时也不知道那个人怎么可能赢钱。

过了一会队友开了一个M,开了半天wa了三发。我一看,是一个spfa的板子题,于是拍上去就过了。

当时已经被压两个题了。

然后跌跌撞撞写过去一个J的dp,

最后冲了一波B,也没写过去,就GG了

rank8跑路

夏老师:要是没进rank10提头来见

我:差点头就没了

3.题目做法

先写下过完的题的做法吧,剩下题补完再更新

C.传染病统计
简单模拟,排个序扫一遍,只要差为2以内就记成一起,最后维护下最大最小值就行

#include
using namespace std;
int n;
bool allcap,cap1,capback;
int T;
int a[15];
int to[15];
int main()
{	
	cin>>T;
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		sort(a+1,a+n+1);
		for(int i=1;i<=n;i++){
			to[i]=i;
		}
		for(int i=1;i<n;i++){
			if(a[i+1]-a[i]<=2) to[i]=i+1;
		}
		int mn=100,mx=1,cnt=0;
		for(int i=1;i<=n;i++){
			cnt++;
			if(to[i]==i+1) continue;
			else {
				mn=min(mn,cnt);
				mx=max(mx,cnt);
				cnt=0;
			}
		}
		printf("%d %d\n",mn,mx);
	}
	return 0;
}

D.阿强与网格
连搜索都不需要,比较下向下和向斜下走哪个更优就好了

#include
#include
#include
using namespace std;
int t;
long long n,m,x,y,ans;
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%lld%lld%lld%lld",&n,&m,&x,&y);
		if(m>n)swap(n,m);
		if(m==1){
			ans=(n-1)*x;
			printf("%lld\n",ans);
			continue;
		}
		if(y>=2*x)ans=(n+m-2)*x;
		else if(y>=x){
			ans=(m-1)*y+(n-m)*x;
		}
		else {
			if((n-m)%2==0)ans=(n-1)*y;
			else ans=(n-2)*y+x;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

E.生活大爆炸
组合数基础
考虑从男的里面选i个,剩下从女生里选k-i个,乘起来,求和就行。

#include
#define ll __int128
using namespace std;
int n,m,t;
ll c(ll x,ll y){
	if(y>x/2)y=x-y;
	ll ret=1;
	for(ll i=x;i>=x-y+1;i--)ret*=i;
	for(ll i=1;i<=y;i++)ret/=i;
	return ret;
}
int main()
{	
	cin>>n>>m>>t;
	ll ans=0;
	for(ll i=4;i<=min(n,t-1);i++){
		if(t-i>m||t-i<1) continue;
		ans+=c(n,i)*c(m,t-i);
	}
	int an[10000],cnt=0;
	while(ans){
		an[++cnt]=ans%10;
		ans/=10;
	}
	for(int i=cnt;i>=1;i--){
		printf("%d",an[i]);
	}
	return 0;
}

F.Capslock
简单模拟

#include
using namespace std;
char s[105];
int n;
bool allcap,cap1,capback;
char to(char x){
	char ret=x;
	if(ret>='A'&&ret<='Z'){
		ret=ret-'A'+'a';
	}
	else{
		ret=ret-'a'+'A';
	}
	return ret;
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	int flag=0,sum=0;
	for(int i=1;i<=n;i++){
		if(s[i]>='A'&&s[i]<='Z'){
			sum++;
		}
	}
	if(sum==n) flag=1;
	if(sum==n-1&&s[1]>='a'&&s[1]<='z') flag=1;
	if(flag){
		for(int i=1;i<=n;i++) s[i]=to(s[i]);
	}
	for(int i=1;i<=n;i++) putchar(s[i]);
	return 0;
}

G.字节类型
会高精应该就秒了
Py的话可能都不需要

#include
using namespace std;
string a;
__int128 x=0;
int main()
{
	cin>>a;
	int len=a.size();
	if(len>=20){
		printf("BigInteger\n");
		return 0;
	}
	for(int i=0;i<len;i++){
		x=x*10+a[i]-'0';
	}
	if(x>9223372036854775807)printf("BigInteger\n");
	else if(x>147483647)printf("long\n");
	else if(x>32767)printf("int\n");
	else if(x>127)printf("short\n");
	else printf("byte\n");
	return 0;
}

I.完美主义
线段树
维护区间的差分数组,最小值不小于0即可

#include
#define ll long long
#define N 300005
using namespace std;
ll a[N];ll b[N];int cnt=0;
int n,q;
struct tree{
	ll a,b;
};tree t[N<<2];
void pushup(int v){
	t[v].b=min(t[v<<1].b,t[v<<1|1].b);
}
void build(int l,int r,int v){
	if(l==r){
		//t[v].a=a[++cnt];
		t[v].b=b[++cnt];
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,v<<1);
	build(mid+1,r,v<<1|1);
	pushup(v);
}
void update(int l,int r,int v,int x,ll val){
	if(l==r){
		t[v].b=val;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) update(l,mid,v<<1,x,val);
	else update(mid+1,r,v<<1|1,x,val);
	pushup(v);
}
ll query(int l,int r,int v,int ql,int qr){
	if(ql<=l&&r<=qr){
		return t[v].b;
	}
	int mid=(l+r)>>1;
	ll ret=3e15;
	if(ql<=mid) ret=min(ret,query(l,mid,v<<1,ql,qr));
	if(mid+1<=qr) ret=min(ret,query(mid+1,r,v<<1|1,ql,qr));
	return ret;
}
int main(){
	cin>>n>>q;
	a[0]=0;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++){
		b[i]=a[i]-a[i-1];
	}
	build(1,n,1);
	while(q--){
		int opt;
		scanf("%d",&opt);
		if(opt==1){
			int x;ll val;
			scanf("%d%lld",&x,&val);
			a[x]=val;
			update(1,n,1,x,a[x]-a[x-1]);
			if(x<n) update(1,n,1,x+1,a[x+1]-a[x]);
		}
		else{
			int l,r;
			scanf("%d%d",&l,&r);
			ll ans=3e15;
			if(l==r){
				printf("Yes\n");
				continue;
			}
			if(l>r){
				printf("No\n");
				continue;
			}
			ans=min(ans,query(1,n,1,l+1,r));
			if(ans<0){
				printf("No\n");
			}
			else printf("Yes\n");
		}
	}
	return 0;
}

J.放棋子
基础dp吧
可以发现第i列和第 k ∗ n + i k*n+i kn+i列放的棋子个数是一样的
那么考虑二维dp,
dp[i][j]表示到第i个位置一共放了j个棋子的方案数
每个位置可以放(0~n)个,所以有一个 o ( n ∗ k ∗ n ) o(n*k*n) o(nkn)的dp方案
第i列乘个快速幂即可,组合数和快速幂都可以预处理成 o ( 1 ) o(1) o(1)

#include
#define ll long long
using namespace std;
const long long MOD=1000000007;
long long n,m,t;
long long dp[105][10050],c[105][105],d[2][105][105],inv[105];
long long C(int xx,int yy) 
{
	if(yy==0)return 1;
	long long ans=1;
	for(int i=xx;i>=xx-yy+1;i--) ans=ans*i%MOD;
	for(int j=1;j<=yy;j++) ans=ans*inv[j]%MOD;
	return ans;
}
long long p(long long xx,long long yy)
{
	long long k=yy,x=xx;
	ll ret=1;
	while(k){
		if(k&1)ret=ret*x%MOD;
		x=x*x%MOD;
		k>>=1;
	}
	return ret;
}
int main()
{
	scanf("%lld%lld%lld",&n,&m,&t);
	inv[1]=1;
	for(int i=2;i<=100;i++)inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
	memset(dp,0,sizeof(dp));
	for(int j=0;j<=100;j++)
	   c[n][j]=C(n,j);
	for(int i=0;i<=100;i++){
		d[0][n][i]=p(c[n][i],m/n);
		d[1][n][i]=p(c[n][i],m/n+1);
	}
	dp[0][0]=1;
	if(t>n*n/2)t=n*n-t;
	for(int i=0;i<n;i++){
		for(int j=0;j<=min(t,i*n);j++){
		 	for(int k=0;k<=n;k++){//printf("%d %d %d!!!\n",i,j,k);
		 		if(j+k>t) continue;
		 		ll now;
		 		if(i+1<=m%n)now=d[1][n][k];
		 		else now=d[0][n][k];
		 		dp[i+1][j+k]=(dp[i+1][j+k]+dp[i][j]*now%MOD)%MOD;
			}
		}
	}
//	for(int i=1;i<=n;i++) {
//		for(int j=0;j<=t;j++) printf("%d ",dp[i][j]);
//		printf("\n");
//	}
printf("%lld\n",dp[n][t]);
	return 0;
}

L.神奇的回答
签到,差点一血

#include
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	int a;
	while(t--) {
		scanf("%d",&a);
		if(a>18) printf("18\n");
		else printf("%d\n",a);
	}
	return 0;
}

M.比赛!
spfa裸板子,一个点入队n次判不可能

#include
#define ll long long
using namespace std;
int n,cnt=0;
char x,y,z;
int sum=0,head[505],tme[505];
char s[505];
int dis[505],in[505];
bool vis[505];
map<char,int>mp;
struct paper{
	int to,nxt;
};
paper edge[1050];
void add(int aa,int bb)
{
//	cout<
	in[bb]++;
	edge[++sum].to=bb; edge[sum].nxt=head[aa]; head[aa]=sum;
}
/*void bfs(int pos,int dp) {
	queue q;
//printf("%d %d\n",pos,dp);
	//vis[pos]=1;
	dep[pos]=max(dep[pos],dp);
	for(int i=head[pos];i!=-1;i=edge[i].nxt) {
		int tt=edge[i].to;
		dfs(tt,dp+1);
	}
//	vis[pos]=0;
}*/
bool noans(int pos) {
	//printf("%d --- %d\n",pos,vis[pos]);
	if(vis[pos]) return 1;
	vis[pos]=1;
	for(int i=head[pos];i!=-1;i=edge[i].nxt) {
		int tt=edge[i].to;
		if(noans(tt)) return 1;
	}
	vis[pos]=0;
	return 0;
}
/*bool noans(int pos){
	if(vis[pos])return 1;
	int ret=0;
	vis[pos]=1;
	for(int i=0;i
void spfa(){
	memset(tme,0,sizeof(tme));
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=cnt;i++) dis[i]=-1e9;
	queue<int>q;
	q.push(0);dis[0]=0;vis[0]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();vis[u]=0;
		for(int i=head[u];i!=-1;i=edge[i].nxt){
			int v=edge[i].to;
		//	printf("%d %d\n",u,v);
			if(dis[v]<dis[u]+1){
				dis[v]=dis[u]+1;
				if(!vis[v]){
					q.push(v);
					vis[v]=1;
					tme[v]++;
					if(tme[v]>cnt) {
						printf("No Answer\n");
						exit(0);
					}
				}
			}
		}
	}
	/*for(int i=1;i<=cnt;i++) {
		printf("%d ",dis[i]);
	}
	printf("\n");*/
}
bool cmp(char xx,char yy) {
	return dis[mp[xx]]<dis[mp[yy]];
}

int main(){
	memset(in,0,sizeof(in));
	memset(vis,0,sizeof(vis));
//	memset(vis,0,sizeof(dep));
	for(int i=0;i<=500;i++){
		head[i]=-1;
	} 
	scanf("%d\n",&n);
	mp.clear();
	for(int i=1;i<=n;i++){
		scanf("%c:%c%c",&y,&x,&z);
		if(i<n) scanf("\n");
		if(x==y||x==z||y==z){
			printf("No Answer\n");
			return 0;
		}
		if(!mp[x]){
			mp[x]=++cnt;
			s[cnt]=x;
		}
		if(!mp[y]){
			mp[y]=++cnt;
			s[cnt]=y;
		}
		if(!mp[z]){
			mp[z]=++cnt;
			s[cnt]=z;
		}
		add(mp[x],mp[y]);
		add(mp[y],mp[z]);
	}
	bool flag=0;
	for(int i=1;i<=cnt;i++) {
		if(in[i]==0){
			flag=1;
			add(0,i);
		}
	}
	if(flag==0) {
		printf("No Answer\n");
		return 0;
	}
	/*if(noans(0)){
		printf("No Answer\n");
		return 0;
	}
	else*/ {
		memset(vis,0,sizeof(vis));
		spfa();
		sort(s+1,s+1+cnt,cmp);
		for(int i=1;i<=cnt;i++) {
			printf("%c",s[i]);
		}
	}
	
}/*
3
A:bd
A:db
b:AC

4
2:13
3:24
4:35
5:46

5
2:13
3:24
4:35
5:46
6:71
*/

4.赛后总结

自己就算有信心最好也大家一起看下再上机。感觉还是尽量把对应的题塞给负责该知识点的队友。
尽量不要all in没人过的题(执着一血是坏文明)
最后桂林加油!

5.补题

来补一发题
H.制造游戏币
场上没看到,开了不可做的题。
发现这个题就是个裸背包题
考虑题目限制一定是若干条链必选成递增序列,先把他处理成0,1,2,…,的必选模式,然后把每个点的价值更新成选他必须付出的代价和,就是裸背包

//by_ileln
//#define LOCAL
#include
using namespace std;
#define IL inline
#define ll long long
#define pii pair<int,int>
#define N 1000005
#define M(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define cinio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define lowbit(x) x & -x
#define dbg(x) cout << #x << " = " << x << endl
ll mod=1e9+7;
int head[N];struct edge{int to,next;};edge e[N<<1];
int cmt=0;int T;
int n,m,k;
int tree[N<<2];void Add(int x,int k){while(x<=n){tree[x]+=k;x+=lowbit(x);}}
int Sum(int x){int ans=0;while(x!=0){ans+=tree[x];x-=lowbit(x);}return ans;}
void add(int u,int v){e[++cmt].to=v;e[cmt].next=head[u];head[u]=cmt;}
template<typename Tp> IL void read(Tp &x){x=0;int f=1;char ch=getchar();while(!isdigit(ch)){
if(ch == '-')f=-1;ch=getchar();}while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}x*=f;}
int buf[42];
template<typename Tp> IL void write(Tp x){int p=0;if(x<0){putchar('-'); x=-x;}if(x==0)
{putchar('0');return;}while(x){buf[++p] = x % 10;x /= 10;}for(int i=p;i;i--) putchar('0'+buf[i]);}
ll quick(ll a,ll b){ll ret=1;ll now=a;while(b){if(b&1){ret*=now;ret%=mod;}now*=now;now%=mod;b>>=1;}return ret;}
ll Inv(ll b){if(b==1)return 1;return(mod-mod/b)*Inv(mod%b)%mod;}
ll fac[N],inv[N];void getc(){fac[0]=inv[0]=1;for(int i=1;i<n;i++)fac[i]=fac[i-1]*i%mod;
inv[n-1]=quick(fac[n-1],mod-2);for(int i=n-2;i;i--)inv[i]=inv[i+1]*(i+1)%mod;}
ll c(int a,int b){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
ll C(ll a,ll b,ll p){if(b>a)return 0;ll res=1;for(ll i=1,j=a;i<=b;i++,j--){res=res*j%p;res=res*quick(i,mod-2)%p;}return res;}
ll lucas(ll n, ll m,ll p){return m?lucas(n/p,m/p,p)*C(n%p,m%p,p)%p:1;}
/*int fa[N][22];int Fa(int i,int k){for(int x=0;x<=int(log2(k));x++)if((1<
/*int B[N],p[N],pcnt=0;void getPrime(int n){B[1]=0;for(int i=2;i<=n;i++){if(!B[i]) p[++pcnt]=i;
for(int j=1;j<=pcnt&&i*p[j]<=n;j++){B[i*p[j]]=1;if(i%p[j]==0)break;}}}*/
map<int,int>mp;
int a[N],vis[N];
ll dp[N];
void dfs(int u){
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		a[v]+=a[u];
		dfs(v);
	}
	if(head[u]) k-=a[u];
}

int main(){
	#ifdef LOCAL
	freopen("in.txt", "r", stdin);
	#endif
	T=1;
	while(T--){
		read(n);read(m);read(k);
		for(int i=1;i<=n;i++){
			read(a[i]);
		}
		for(int i=1;i<=m;i++){
			int u,v;read(u);read(v);
			add(u,v);vis[v]=1;
		}
		for(int i=1;i<=n;i++){
			if(!vis[i]) dfs(i);
		}
		dp[0]=1;
		for(int i=1;i<=n;i++){
			for(int j=a[i];j<=k;j++){
				dp[j]=(dp[j-a[i]]+dp[j])%mod;
			}
		}
		write(dp[k]);
	}
	return 0;
}

你可能感兴趣的:(生活/其他,ACM,c++)