个人赛补题
round 1
范围很小用暴力+贪心,左右枚举,先拿再放。尽量放小的所以需要排下序
include
include "map"
include "algorithm"
include "cmath"
include "vector"
include "set"
include "queue"
define int long long
using namespace std;
void solve(){
int n,k;
cin>>n>>k;
int s[n+5];
for(int i=1;i<=n;i++)
cin>>s[i];
int ans=-1e9;
for(int i=0;i<=min(n,k);i++){
for(int j=0;j<=min(n,k)-i;j++){
vector
int sd=0;
for(int q=1;q<=i;q++) {
vt.emplace_back(s[q]);
sd+=s[q];
}
for(int q=1;q<=j;q++) {
vt.emplace_back(s[n - q + 1]);
sd+=s[n-q+1];
}
sort(vt.begin(),vt.end());
for(int q=1;q<=k-i-j&&q<=vt.size();q++){
if(vt[q-1]<0)
sd-=vt[q-1];
else
break;
}
ans=max(ans,sd);
}
}
cout<<ans;
}
signed main()
{
int t=1;
//cin>>t;
while(t--){
solve();
}
}
这道题偷了个模板,我之前求组合数都是用的动态规划优化的,没想到题解用的优化的更猛。啥也别说了偷了
long long a(long long x,long long y){
long long ret=1;
while(y)
{
if(y&1)ret=retx%M;
x=xx%M;
y>>=1;
}
return ret;
}
long long b(long long x,long long y){//排列组合
long long sum=1,num=1;
for(int i=x;i>=x-y+1;i--)sum=sumi%M;
for(int i=1;i<=y;i++)num=numi%M;
return sum*a(num,M-2)%M;
}
打个比方求C(100,3)
cout<<b(100,3);
回到正题
考虑两个之间行距为 i 都可以随便选择一列,从 n−i 个行距为 i 的行组合中挑选一个,然后再选择剩余的k−2 个,那么可以推出方案数为i×(n−i)×m×m 再乘一个nm−2 和k−2 的排列组合就行了。
include<bits/stdc++.h>
define int long long
using namespace std;
const long long M=1000000007;
long long a(long long x,long long y){
long long ret=1;
while(y)
{
if(y&1)ret=retx%M;
x=xx%M;
y>>=1;
}
return ret;
}
long long b(long long x,long long y){//排列组合
long long sum=1,num=1;
for(int i=x;i>=x-y+1;i--)sum=sumi%M;
for(int i=1;i<=y;i++)num=numi%M;
return suma(num,M-2)%M;
}
signed main(){
int n,m,k;
cin>>n>>m>>k;
int ans=0;
for(int i=0;i<n;i++){
ans+=(i%M(n-i)%Mm%Mm%M)%M;
ans%=M;
}
for(int i=0;i<m;i++){
ans+=(i%M(m-i)%Mn%Mn%M)%M;
ans%=M;
}
ans=b(n*m-2,k);
ans%=M;
cout<<ans;
return 0;
}
round 2
刚开始写这道题因为看到范围比较小,所以打算直接把图形输出,后来逐渐尝试发现根本不行,到6的时候就要输出700多行了。看完题解后发现可以搜索。从8个方向去搜索,其中'.'赋为0,'#'为1.
include<bits/stdc++.h>
using namespace std;
int a[2000][2000];//0:黑,1:白
void dfs(int x,int y,int k){
if(k==0){
a[x][y]=0;
return ;
}
dfs(x,y,k-1);
dfs(x+pow(3,k-1),y,k-1);
dfs(x+pow(3,k-1)2,y,k-1);
dfs(x,y+pow(3,k-1),k-1);
dfs(x,y+pow(3,k-1)2,k-1);
dfs(x+pow(3,k-1),y+pow(3,k-1)2,k-1);
dfs(x+pow(3,k-1)2,y+pow(3,k-1),k-1);
dfs(x+pow(3,k-1)2,y+pow(3,k-1)2,k-1);
for(int i=x+pow(3,k-1);i<x+pow(3,k-1)2;i++){
for(int j=y+pow(3,k-1);j<y+pow(3,k-1)2;j++){
a[i][j]=1;
}
}
}
int main(){
int n;
cin>>n;
dfs(0,0,n);
for(int i=0;i<pow(3,n);i++){
for(int j=0;j<pow(3,n);j++){
if(a[i][j]) cout<<'.';
else cout<<'#';
}
cout<<endl;
}
}
因为节点 到最近黑色节点的最短距离已经是最小值,所以我们把最短距离小于给定距离的节点全部排除。然后判断对于一个节点,是否所有的距离等于给定距离的节点都被排除了。如果是,说明无解,输出 -1,结束程序。若不存在无解,则说明一定有解。把排除成为黑色节点的全部输出为白色节点,否则输出位黑色节点。
include <bits/stdc++.h>
define int long long
using namespace std;
pair<int,int> p1[2005],p2[2005];
map<int,int> ma;
map<int,set
void solve(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
p1[i]={a,b};
mp[a].insert(b);
mp[b].insert(a);
}
int k=1;
cin>>k;
for(int i=1;i<=k;i++){
int a,b;
cin>>a>>b;
p2[i]={a,b};
}
for(int i=1;i<=k;i++){
queue
map<int,int> mo;
num.push(p2[i].first);
cnt.push(0);
while(num.size()!=0){
int x=num.front(),y=cnt.front();
num.pop(),cnt.pop();
if(mo[x]||yp2[i].second) continue;
mo[x]=1,ma[x]=1;
for(auto x:mp[x]){
num.push(x);
cnt.push(y+1);
}
}
}
for(int i=1;i<=k;i++){
queue
int o=0;
bool f=false;
map<int,int> mo;
num.push(p2[i].first);
cnt.push(0);
while(num.size()!=0) {
int x=num.front(),y=cnt.front();
num.pop(),cnt.pop();
if(mo[x]) continue;
if(y
if(!ma[x]){
f=true;
break;
}
continue;
}
mo[x]=1,ma[x]=1;
for(auto x:mp[x]){
num.push(x);
cnt.push(y+1);
}
}
if(f==false){
cout<<"No\n";
return;
}
}
cout<<"Yes\n";
for(int i=1;i<=n;i++){
if(ma[i]){
cout<<'0';
}
else
cout<<'1';
}
}
signed main(){
int t=1;
//cin>>t;
while(t--)
solve();
}
Round 3
这道题是一道dp,但是这个题目有一点错误,它并没有说多组输入,愣是给我交了十几发才发现。这个就是二维dp,dp[i][j]其中i表示前i个数字中有j对的最小代价是什么。有两种转移方式。一个是加上最后的i,一个是不加最后的i也就是dp[i-1][j]。二者取最小。
include
include "algorithm"
include "cstring"
define inf 0x3f3f3f3f
using namespace std;
int dp[2005][2005];
int s[20005];
int main(){
int n,k;
while(cin>>n>>k){
memset(s,0,sizeof(s));
memset(dp,inf,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++){
cin>>s[i];
dp[i][0]=0;
}
sort(s+1,s+n+1);
for(int i=2;i<=n;i++){
for(int j=1;j<=k;j++){
dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+((s[i]-s[i-1])*(s[i]-s[i-1])));
}
}
cout<<dp[n][k]<<'\n';
}
}
补E题时找到个集合求子集的板子,说实话还挺好用的。特在此收藏
输入n个数,把数据存放在数组a中。a是从0开始存放的。把子集存在vector
for(int i=1;i<(1<<n);i++){
int s=0;
vector
for(int j=0;j<n;j++){
if(i>>j&1){
temp.push_back(j);
s=(s+a[j])%200;
}
}
}
这个学到了鸽笼原理。因为是%200,所以余数一定小于200.所以求子集到8就够了。前256个子集中一定有两个子集余数相同。这时候就可以枚举了
include <bits/stdc++.h>
define int long long
using namespace std;
map<int,vector
void solve(){
int n;
cin>>n;
int s[n+5];
for(int i=0;i<n;i++)
cin>>s[i];
n=min(n,(int)8);
for(int i=1;i<pow(2,n);i++) {
vector<int> vt;
int num=0;
for(int j=0;j<n;j++){
if(i>>j&1){
vt.emplace_back(j+1);
num=(num+s[j])%200;
}
}
if(ma[num].size()==0){
ma[num]=vt;
}
else{
cout<<"Yes\n";
cout<<ma[num].size()<<' ';
for(auto x:ma[num]){
cout<<x<<' ';
}
cout<<'\n';
cout<<vt.size()<<' ';
for(auto x:vt){
cout<<x<<' ';
}
return;
}
}
cout<<"No\n";
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
solve();
return 0;
}
热身赛一
这道题正解是三分,但是我没用正解,用的是暴力+优化也能解决,因为分为四段,我是枚举中间点,然后在中间点的两端再去枚举,但是这样肯定会超时。优化的时候可以发现有很多部分是可以省略的。这部分就是减少代码时间的关键。 long long ans=1e18,p1,p2,p3,p4;
int l=1,r=3;//把l,r写在外面,不断循环就不用重头开始了
for(int i=2;i<=n-2;i++)
代码如下
include<bits/stdc++.h>
using namespace std;
long long fg[200005];
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&fg[i]);
fg[i]+=fg[i-1];
}
long long ans=1e18,p1,p2,p3,p4;
int l=1,r=3;
for(int i=2;i<=n-2;i++){
while(l<i&&abs((fg[i]-fg[l])-(fg[l]-fg[0]))>=abs((fg[i]-fg[l+1])-(fg[l+1]-fg[0])))
l++;
while(r<n&&abs((fg[n]-fg[r])-(fg[r]-fg[i]))>=abs((fg[n]-fg[r+1])-(fg[r+1]-fg[i])))
r++;
p1=fg[l]-fg[0];
p2=fg[i]-fg[l];
p3=fg[r]-fg[i];
p4=fg[n]-fg[r];
ans=min(max(max(max(p1,p2),p3),p4)-min(min(min(p1,p2),p3),p4),ans);
}
printf("%lld",ans);
return 0;
}
说实话这道题看半天没有看懂,后来才发现就是一个floyd的模板题。给你的10*10数组就是每一个点到其他点的距离。用floyd正好
include<bits/stdc++.h>
define INF 0x7fffffff/2 //int最大值
using namespace std;
int h,w;
int x,dis[15][15];
void floyd(){
for(int k=0;k<=9;k++){ //枚举每一个点
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++){
if(dis[i][k]!=INF and dis[k][j]!=INF) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); //松弛操作
}
}
}
}
int main(){
scanf("%d%d",&h,&w);
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++){ //i,j分别枚举0-9中的数字,也就是这条边连接的两个节点
scanf("%d",&dis[i][j]); //dis数组储存边权
}
}
floyd();
int ans=0;
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
scanf("%d",&x); //在输入时在线处理
if(abs(x)==1) continue; //如果这个点是1或-1,则不需要加在ans上
ans+=dis[x][1]; //累加x到1的最短路径
}
}
printf("%d",ans);
return 0;
}
热身赛二
这道题当时已经推出来公式了,但是如何枚举倒是没有想到,我们设这个商为 x,那么余数也为 x,而被除数 = 商 × 除数 + 余数,于是就有 n=mx+x=x(m+1),所以我们只需枚举 x即可求出 m.
include<bits/stdc++.h>
define int long long
using namespace std;
void solve(){
int n;
cin>>n;
int ans=0;
for(int i=1;i*(i+1)<n;i++){
if(n%i==0){
ans+=(n/i-1);
}
}
cout<<ans;
}
signed main()
{
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
这个是期望dp,当时不自量力去做,后来补题的时候发现好难啊。。。
第 i 面镜子会有两种情况。
第一种:镜子回答"漂亮",花一天走到下一面镜子。这种情况的贡献是 pi(dp(i+1)+1);
第二种:镜子回答"不漂亮",花一天走到第一面镜子。这种情况的贡献是:(1-pi)(dp1+1)
最终dpi=pi×(dp(i+1)+1)+(1−pi)×(dp1+1)=pi×dp(i+1)+(1−pi)×dp1+1;
但是这个还要dp1推一下,最终推导的公式因为符号的问题打不到博客上,这个还需要从后往前算
include<bits/stdc++.h>
using namespace std;
define int long long
const int mod=998244353;
int qwe(int a,int b,int p){
int ans=1;
while(b){
if(b&1)ans=ansa%p;
a=aa%p;
b/=2;
}
return ans;
}
int n;
int a[200010],ans,tmp;
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)
cin>>a[i];
tmp=1;
for(int i=n;i>=1;i--){
tmp=tmp100%modqwe(a[i],mod-2,mod)%mod;
ans=(ans+tmp)%mod;
}
printf("%lld",ans);
return 0;
}
友谊赛
先求ab的前k项,再求abc的前k项。但是唯一的难点就是n^2的复杂度如何减到n。题解中用到了优先队列我觉得这个很值得参考
for (int i = 1; i <= y; i++) {
qt.push({a[1] + b[i], i});
pb[i] = 1;
}
for (int i = 1; i <= w && i <= x * y; i++) {
int u = qt.top().second;
int y = qt.top().first;
num[i] = y;
qt.pop();
qt.push(make_pair(a[++pb[u]] + b[u], u));
}
上述代码实现了ab的前w项,但是复杂度只有n*logn,结合了优先队列进行使用。
include<bits/stdc++.h>
using namespace std;
define int long long
int a[200005],b[200005],c[200005], num[200005],pb[200005],pc[200005];
priority_queue<pair<int,int>> qt;
bool compare(int a,int b){
return a>b;
}
signed main() {
int x, y, z, w;
cin >> x >> y >> z >> w;
for (int i = 1; i <= x; i++)
cin >> a[i];
for (int i = 1; i <= y; i++)
cin >> b[i];
for (int i = 1; i <= z; i++)
cin >> c[i];
sort(a + 1, a + x + 1, compare);
for (int i = 1; i <= y; i++) {
qt.push({a[1] + b[i], i});
pb[i] = 1;
}
for (int i = 1; i <= w && i <= x * y; i++) {
int u = qt.top().second;
int y = qt.top().first;
num[i] = y;
qt.pop();
qt.push(make_pair(a[++pb[u]] + b[u], u));
}
while(!qt.empty())
qt.pop();//清空q
for(int i=1;i<=z;i++){
qt.push(make_pair(c[i]+num[1],i));
pc[i]=1;
}
for(int i=1;i<=w;i++){
int bh=qt.top().second;
cout<<qt.top().first<<endl;
qt.pop();
qt.push(make_pair(num[++pc[bh]]+c[bh],bh));
}
return 0;
}
二分答案。这个矩阵的每一排都是递增的,所以二分ans,去计算有多少个数等于ans,有多少个数小于ans,如果小于ans的数不多于−1k−1个并且小于等于ans的数不少于k个,那么当前ans就是答案。
include<bits/stdc++.h>
using namespace std;
long long n,m,k;
bool qwe(long long x)
{
long long sum=0;
for(int i=1;i<=n;i++)
sum+=min(m,x/i);
if(sum>=k)
return true;
else
return false;
}
int main()
{
cin>>n>>m>>k;
long long pow=n*m;
long long l=1,r=pow;
while(l<r){
long long mid=(l+r)>>1;
if(qwe(mid))
r=mid;
else
l=mid+1;
}
cout<<l;
}