2020 CCPC Wannafly Winter Camp Day6 解题报告

N


白给题,⽆论怎么进⾏合并,最后的答案⼀定是 a[1…n] 两两的乘积之和。


n = int(input())
a = list(map(int, input().split()))
ans = 0
for i in range(0, n):
    for j in range(i+1, n):
        ans += a[i] * a[j]
print(ans)

K


白给题,看样例知规律。


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=1e5+7;
int n;
int Ans[N],t=0;

int main(){
	n=input();
	int l=1,r=n;
	while(l<=r){
		Ans[l++]=++t;
		if(l>r) break;
		Ans[r--]=++t;
	}
	for(int i=1;i<=n;i++) printf("%d%c",Ans[i],i==n? '\n':' ');
}

C


最好情况:普通随从破盾,剧毒随从杀怪。

最坏情况:剧毒随从破盾。

模拟即可。


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=1007;

char s[N];

int Solve1(int n,int a,int b,int c,int d){
	int res=0;
	for(int i=1;i<=n;i++){
		if(s[i]=='1'){
			if(c) c--,res++;
			else if(d) d--,c++;
			else if(a) a--,res++;
			else if(b) b--,a++;
		}else{
			if(d) d--,c++;
			else if(c) continue;
			else if(b) b--,a++;
			else if(a) continue;
		}
	}
	return res;
}

int Solve2(int n,int a,int b,int c,int d){
	int res=0;
	for(int i=1;i<=n;i++){
		if(s[i]=='1'){
			if(d) d--,c++;
			else if(c) c--,res++;
			else if(b) b--,a++;
			else if(a) a--,res++;
		}else{
			if(c) continue;
			else if(d) d--,c++;
			else if(a) continue;
			else if(b) b--,a++;
		}
	}
	return res;
}

int main(){
	int T=input();
	while(T--){
		int n=input(),a=input(),b=input(),c=input(),d=input();
		scanf("%s",s+1);
		printf("%d %d\n",Solve1(n,a,b,c,d),Solve2(n,a,b,c,d));
	}
}

L


BFS


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

#define PII pair<int,int>
#define fr first
#define sc second
#define mp make_pair

const int N=107;

int t[8][2]={{1,2},
			 {1,-2},
			 {-1,2},
			 {-1,-2},
			 {2,1},
			 {2,-1},
			 {-2,1},
			 {-2,-1}
			};
int tt[8][2]={{0,1},
			 {0,-1},
			 {0,1},
			 {0,-1},
			 {1,0},
			 {1,0},
			 {-1,0},
			 {-1,0}
			};

int Map[N][N];
int Ans[N][N],vis[N][N];
char s[N];
queue <PII> q;

int main(){
	int n=input(),m=input();
	PII sta;

	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=m;j++){
			if(s[j]=='X') Map[i][j]=1;
			else Map[i][j]=0;

			if(s[j]=='M') sta=mp(i,j);
			Ans[i][j]=0x3f3f3f3f;
		}
	}

	q.push(sta);
	vis[sta.fr][sta.sc]=1;
	Ans[sta.fr][sta.sc]=0;

	while(!q.empty()){
		int x=q.front().fr,y=q.front().sc;
		vis[x][y]=0;
		q.pop();
		for(int i=0;i<=7;i++){
			int tx=x+t[i][0],ty=y+t[i][1];
			int ttx=x+tt[i][0],tty=y+tt[i][1];
			if(1<=tx&&tx<=n&&1<=ty&&ty<=m&&Map[ttx][tty]==0&&Map[tx][ty]==0){
				if(Ans[x][y]+1<Ans[tx][ty]){
					Ans[tx][ty]=Ans[x][y]+1;
					if(!vis[tx][ty]){
						q.push(mp(tx,ty));
						vis[tx][ty]=1;
					}
				}
			}
		}
		
	}

	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			// cout<<Ans[i][j]<<endl;
			printf("%d ",Ans[i][j]==0x3f3f3f3f? -1:Ans[i][j]);
		}printf("\n");
	}
}

M


模拟就好了


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=1e2+7,M=20;
ll a[N][M],mx[N][M];

int n,m,w;
ll Ans[N];
int num[N],vis[N],vvis[N][N];

int main(){
	n=input(),m=input(),w=input();
	for(int i=1;i<=n;i++) Ans[i]=-1;
	for(int i=1;i<=w;i++){
		int x=input(),y=input(),c=input();
		vis[x]=1;
		if(c){
			if(vvis[x][y]==0)num[y]++,vvis[x][y]=1;
			a[x][y]=0;
		}else{
			a[x][y]++;
			mx[x][y]=max(mx[x][y],a[x][y]);
		}
	}

	for(int i=1;i<=n;i++){
		int f=1;
		for(int j=1;j<=m;j++)
			if(!vvis[i][j]) f=0;
		if(f) Ans[i]=0;
	}

	for(int i=1;i<=n;i++){
		if(Ans[i]!=-1) continue;
		Ans[i]=0;
		if(vis[i]==0){
			Ans[i]=998244353;
			continue;
		}
		int f=1;
		for(int j=1;j<=m;j++){
			if(vvis[i][j])
				f=0,Ans[i]+=mx[i][j]*mx[i][j];

			if(!vvis[i][j]) Ans[i]+=2LL*mx[i][j]*mx[i][j];
			if(vvis[i][j]==0&&num[j]){
				Ans[i]+=20;
				if(num[j]>=n/2) Ans[i]+=10;
			}
		}
		if(f) Ans[i]=1000000;
	}
	for(int i=1;i<=n;i++)
		printf("%lld\n",Ans[i]);
}

F


不难知道题目中所给的图是完全图,也就说对于任何一条边与图中任意一个非端点都可以组成一个三角形,然后就变成一个组合计数问题了。直接统计答案不太方便,我们可以统计不满足条件的方案然后容斥一下就解决了。


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=5007;
#define pb push_back

struct edge{
	int u,v,w;
};

vector <edge> G;
ll sum;
ll cnt[N][2];

int main(){
	ll n=input();
	sum=n*(n-1)*(n-2)/(3*2*1);
	ll A=input(),B=input(),C=input(),P=input(),D=input();

	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			ll tmp=(A*(i+j)*(i+j)+B*(i-j)*(i-j)+C)%P;
			if(tmp>D){
				cnt[i][1]++,cnt[j][1]++;
				G.pb((edge){i,j,1});
			}else{
				cnt[i][0]++,cnt[j][0]++;
				G.pb((edge){i,j,0});
			}
		}
	}

	ll Ans=0;

	for(auto v:G){
		if(v.w==1){
			Ans+=cnt[v.u][0],
			Ans+=cnt[v.v][0];
		}else{
			Ans+=cnt[v.u][1],
			Ans+=cnt[v.v][1];
		}
	}

	printf("%lld\n",sum-Ans/4);
}

G


贪心。


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=107;

int a[N],Ans[N];

int main(){
	int T=input();
	while(T--){
		int n=input(),now=0,t=1;
		for(int i=1;i<=n;i++){
			a[i]=input();
		}

		while(now<n){
			for(int i=n;i>=1;i--)
				if(a[i]==t) Ans[i]=++now;
			
			for(int i=1;i<=n;i++){
				if(a[i]==-1){a[i]=t,Ans[i]=++now;break;}
				else if(a[i]==t) break;
			}
			t++;
		}

		for(int i=1;i<=n;i++){
			printf("%d ",Ans[i]);
		}printf("\n");
	}
}

H


这个题看起来有一个奇奇怪怪的异或操作,看起来区间不再连续,实际上区间变为了\(logn\)个区间,所以只需要查询这\(logn\)个区间就行了。


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

#define pb push_back

const int N=1e5+7;
const ll mod=998244353;

ll sum[N];
int a[N];
ll v[N],cnt=0;
int n,q;

ll ask(int x){
	int pos=upper_bound(v+1,v+1+cnt,x)-v;
	if(pos==1) return 0;
	pos--;
	ll res=sum[pos-1];
	ll k=upper_bound(a,a+n,v[pos])-a;
	res=(res+(x-v[pos]+1)*k%mod*k%mod)%mod;
	return res;
}

ll ask(int l,int r){
	return (ask(r)-ask(l-1))%mod;
}

ll query(int t,int x){
	if(t<0) return 0;
	int cur=0;ll res=0;
	for(int i=30;i>=0;i--){
		int u=(x>>i&1);
		if(t>>i&1){
			res+=ask(cur|(u<<i),(cur|(u<<i))+(1<<i)-1);
			cur+=((1<<i)^(u<<i));
		}else cur|=(u<<i);
	}
	res+=ask(cur,cur);
	return res;
}

int main(){
	n=input(),q=input();
	for(int i=0;i<n;i++)
		a[i]=input(),v[++cnt]=a[i];
	sort(a,a+n);
	sort(v+1,v+1+cnt);
	cnt=unique(v+1,v+cnt+1)-v-1;

	for(int i=1;i<cnt;i++){
		ll k=upper_bound(a,a+n,v[i])-a;
		sum[i]=(sum[i-1]+(v[i+1]-v[i])%mod*k%mod*k%mod)%mod;
	}

	for(int i=1;i<=q;i++){
		int l=input(),r=input(),x=input();
		ll Ans=((query(r,x)-query(l-1,x))%mod+mod)%mod;
		printf("%lld\n",Ans);
	}

}

I


最后的答案肯定是若干个连续的区域最大值,我们不妨借用背包问题的思想来确定这些区间的最大值和长度。


#include <bits/stdc++.h>

using namespace std;

#define ll long long
ll input(){
	ll x=0,f=0;char ch=getchar();
	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return f? -x:x;
}

const int N=57;

int n,a[N],dp[N][N];

int main(){
	int T=input();
	while(T--){
		memset(dp,0,sizeof(dp));
		n=input();
		for(int i=1;i<=n;i++)
			a[i]=input();

		for(int i=1;i<=n;i++){
			int mx=a[i];
			for(int j=i-1;j>=0;j--){
				int c=(i-j)/2;
				for(int k=0;k+c<=i;k++){
					dp[i][k+c]=max(dp[i][k+c],dp[j][k]+mx*(i-j));
				}
				mx=max(a[j],mx);
			}
		}

		for(int i=1;i<=n;i++){
			printf("%lld%c",dp[n][i],i==n?'\n':' ');
		}
	}
}

posted @ 2020-03-02 17:06  _aether  阅读(304)  评论(0编辑  收藏  举报