Fillomino 2
题意:给n*n的方格,主要看左下部分,输入整数n,n个整数a[i],表示(i,i)位置上的数字,要求划分出一个连通块,块内的元素个数恰为对角线上的数字。
思路:贪心,对于每次扩展首先往左扩,行不通往下扩,最后往右扩。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<cctype>
#define debug(x) cout<<#x<<"="<<x<<'\n';
#define int long long
#define eb emplace_back
#define endl '\n'
#define per(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
int a[510][510]={0},b[510][510]={0};
int T,n,m,k,ans;
void dfs(int x,int y,int k)
{
if(b[k][k]==1)return ;
if((y-1)>=1&&!a[x][y-1])
{
a[x][y-1]=a[k][k];
b[k][k]--;
dfs(x,y-1,k);
}
else if(x+1<=n&&!a[x+1][y])
{
a[x+1][y]=a[k][k];
b[k][k]--;
dfs(x+1,y,k);
}
else
{
a[x][y+1]=a[k][k];
b[k][k]--;
dfs(x,y+1,k);
}
}
void solve()
{
cin>>n;
per(i,1,n)cin>>a[i][i],b[i][i]=a[i][i];
per(i,1,n)dfs(i,i,i);
per(i,1,n)
{
per(j,1,i)
cout<<a[i][j]<<' ';
cout<<endl;
}
}
signed main()
{
// cin>>T;
// while(T--)
solve();
}
B. AGAGA XOOORRR
题意:n个数字,询问是否能通过任意次数,任取两个数进行按位与,并将该结果放入数组,最后使数字剩下最少两个相同的数字。
思路:倒着看,根据按位与的性质,大致可分为两种情况,一是最后的结果有偶数个相同的数,此时所有数按位与为0。二是最后结果有奇数个相同的数字,此时所有数的按位与为设x,在重新按位与,如果此时结果等于x,cnt++。按位与结果置为0继续进行操作。最后查看cnt是否>=3即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<cctype>
#define debug(x) cout<<#x<<"="<<x<<'\n';
#define int long long
#define eb emplace_back
#define endl '\n'
#define per(i,l,r) for(int i=l;i<=r;i++)
#define rep(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
int a[2010];
int T,n,m,k,ans;
void solve()
{
int ans1=0,ans=0;
cin>>n;
per(i,1,n)
{
cin>>a[i];
ans^=a[i];
}
if(ans==0)
{
cout<<"YES"<<endl;
return ;
}
int cnt=0;
per(i,1,n)
{
ans1^=a[i];
if(ans1==ans)
{
ans1=0;
cnt++;
}
}
if(cnt>=3)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
signed main()
{
cin>>T;
while(T--)
solve();
}
C. Phoenix and Socks
题意:共有n只袜子,l只左袜子,r只右袜子,下一行n个数a[i]代表袜子的颜色。
可以进行以下操作:1、将左袜子变为右袜子2、将袜子的颜色进行更改。每次操作操作次数+1,问能组成n/2双袜子的最小操作数。
思路:首先消除颜色相同的左右袜子,此时操作数无变化。之后尝试将颜色相同,左右也相同的袜子变化方向,此时操作时加1,最后将剩下的袜子(左右不同颜色也不同)改变颜色和左右。对比此时是左袜子剩的多还是右袜子剩的多,如果左袜子剩的多就看左边的颜色数组计算,最后ans+(l-r)/2表示将多出的左袜子转换为右袜子,ans+(l+r)/2表示将部分袜子换颜色。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,l,r,nl,nr,ans;
int cl[200010],cr[200010],a[200010],b[200010];
void solve()
{
ans=0;
cin>>n>>nl>>nr;l=nl,r=nr;
memset(cl,0,sizeof cl);
memset(cr,0,sizeof cr);
memset(a,0,sizeof a);
memset(b,0,sizeof b);
for(int i=0;i<nl;i++)
{
cin>>a[i];
cl[a[i]]++;
//l--;
}
for(int i=0;i<nr;i++)
{
cin>>b[i];
if(cl[b[i]])
{
cl[b[i]]--;
l--;
r--;
}
else cr[b[i]]++;
}
// cout<<l<<' '<<r<<' '<<endl;
if(l>=r)
{
for(int i=0;i<nl;i++)
{
if(cl[a[i]]>=2&&l>r)
{
ans++;
cl[a[i]]-=2;
l-=2;
}
}
// cout<<l<<' '<<r<<endl;
ans+=(l-r)/2+(r+l)/2;
}
else
{
for(int i=0;i<nr;i++)
{
if(cr[b[i]]>=2&&r>l)
{
ans++;
cr[b[i]]-=2;
r-=2;
}
}
ans+=(r-l)/2+(r+l)/2;
}
cout<<ans<<endl;
}
signed main()
{
cin>>T;
while(T--)
solve();
}
PS:在这个位置
if(l>=r)
{
for(int i=0;i<nl;i++)
{
if(cl[a[i]]>=2&&l>r)
{
ans++;
cl[a[i]]-=2;
l-=2;
}
}
之前依次遍历颜色过不去,现在还没有找出原因QAQ,大神们看出来的话请说一下(递话筒)
D. Berland Regional
题意:输入n,之后输入n个ui表示学校,n个si表示学生的学习能力,找出k分别取1-n时各学校派出的学生的总编程能力的最值。
思路:首先按照学校不同将学生放入对应map中,对学生的编程能力从大到小排序,算出对应前缀和,ans加一下各学院的就可以了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n;
bool cmp(int a,int b)
{
return a>b;
}
void solve()
{
cin>>n;
map<int,vector<int>> mp;
vector<int> un(n+1),ans(n+1);
for(int i=1;i<=n;i++)cin>>un[i];
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
mp[un[i]].push_back(x);
}
for(auto [u,x]:mp)
{
sort(x.begin(),x.end(),cmp);
int len=x.size();
vector<int> p(len+1);
for(int i=1;i<=len;i++)p[i]=p[i-1]+x[i-1];
for(int i=1;i<=len;i++)ans[i]=ans[i]+p[len-len%i];
}
for(int i=1;i<=n;i++)cout<<ans[i]<<' ';
cout<<endl;
}
signed main()
{
cin>>T;
while(T--)
solve();
}
哈哈又学到一个
for(auto [u,x]:mp)//遍历map
E. Restoring the Permutation
题意:给出数组q,qi=max(p1,p2,…,pi).求p数组的最小字典序和最大字典序
思路:最开始想着通过遍历求出对应的数值,T在了第三了,最后通过set求出。
求最小字典序时,若数字第一次出现就输出该数字,否则输出比该数字小的且未输出过的最小的数字。
求最大字典序是,若数字第一次出现就输出该数字,否则输出比该数字小的且未输出过的最大的数字。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n;
int a[200010];
void solve()
{
cin>>n;
set<int> s;
for(int i=1;i<=n;i++)
{
s.insert(i);
}
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
if(a[i]!=a[i-1])
{
cout<<a[i]<<' ';s.erase(a[i]);
}
else cout<<*s.begin()<<' ',s.erase(*s.begin());
for(int i=1;i<=n;i++)s.insert(i);cout<<endl;
for(int i=1;i<=n;i++)
{
if(a[i]==a[i-1])
{
cout<<*prev(s.lower_bound(a[i]))<<' ';
s.erase(*prev(s.lower_bound(a[i])));
}
else cout<<a[i]<<' ';s.erase(a[i]);
}
cout<<endl;
}
signed main()
{
cin>>T;
while(T--)
solve();
}
F. Planar Reflections
题意:有n个平面和D(k)光束,每次穿过一个平面会反射出一个反方向的D(k-1),k=1时不再反射,问最后有多少个不同的光线
例如当n=2,k=3时
此时有不同的光线 {D(3),D(2),D(2),D(1)},答案为4;
思路:动态规划(没想到QAQ)dp[j][i]表示穿过j个平面此时k为i的不同光线数。转移方程为
d
p
[
j
]
[
i
]
=
(
d
p
[
n
−
j
]
[
i
−
1
]
+
d
p
[
j
−
1
]
[
i
]
)
dp[j][i]=(dp[n-j][i-1]+dp[j-1][i])%mod;
dp[j][i]=(dp[n−j][i−1]+dp[j−1][i])
此状态由穿过j-1个平面,k为i和穿过n-j个平面,k=i-1共同组成。循环顺序为先循环光束,再循环平面。首先讨论光束的分裂次序。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k,ans;
int mod=1e9+7;
int dp[1010][1010];
void solve()
{
memset(dp,0,sizeof dp);
cin>>n>>k;
for(int i=1;i<=k;i++)dp[0][i]=1;
for(int i=1;i<=n;i++)dp[i][1]=1;
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
dp[j][i]=(dp[n-j][i-1]+dp[j-1][i])%mod;
cout<<dp[n][k]<<endl;
}
signed main()
{
cin>>T;
while(T--)
solve();
}
G. Building a Fence
题意:给出各位置路面高度,两个栅栏需要互相连通,每个栅栏距离地面不应超过k-1,问所给样例是否满足条件
思路:每次计算出下一个栅栏的范围,判断是否符合范围即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k,h[200010];
void solve()
{
cin>>n>>k;
for(int i=0;i<n;i++)cin>>h[i];
int l=h[0],r=h[0]+k;
bool f=0;
for(int i=1;i<n-1;i++)
{
if(l>=h[i]+k-1+k)
{
f=1;
break;
}
if(r<=h[i])
{
f=1;
break;
}
l=max(l-k+1,h[i]);
r = min(r - 1, h[i] + k - 1) + k;//r-1由于最小要有1米连接
}
if(l>=h[n-1]+k)f=1;
if(r<=h[n-1])f=1;
if(f)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
signed main()
{
cin>>T;
while(T--)
solve();
}
H. Ceil Divisions
题意:给一个数字n得数字a[i]=i,判断能否通过选择x,y;x!=y;使
a
x
=
⌈
a
x
/
a
y
⌉
ax=⌈ax/ay⌉
ax=⌈ax/ay⌉
最终使数组只有1个2,剩下的都是1、
思路:对于n找到y大于n/y上取整的数,将这些书都除以n。之后将n除以该数字两次,递归调用将参数改为该数字即可。
#include<bits/stdc++.h>
//#define int long long
using namespace std;
int T,n;
void w(int n,vector<pair<int,int>> &ans)
{
if(n==2)return ;
int y = max((int)1, (int)sqrt(n) - 1);
while (y < (n + y - 1) / y)
y++;
for(int i=y+1;i<n;i++)
ans.emplace_back(i,n);
ans.emplace_back(n,y);
ans.emplace_back(n,y);
w(y,ans);
}
void solve()
{
cin>>n;
vector<pair<int,int>> ans;
w(n,ans);
cout<<ans.size()<<endl;
for(auto x:ans)cout<<x.first<<' '<<x.second<<endl;
}
int main()
{
cin>>T;
while(T--)
solve();
}
I. Pekora and Trampoline
题意:从任意一点i起跳,每次可到达i+a[i]的位置,此时a[i]–;减到1时就不再减小,问至少跳几次使所有的a[i]都变为1
思路:对于每个i而言,可对i+2至i+a[i]产生影响,将所有的影响相加,不够的次数加入ans即可,够的话b[i+1]+=(b[i]-a[i]+1);
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,a[200010],b[200010];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],b[i]=0;
for(int i=1;i<=n;i++)
for(int j=i+2;j<=min(n,a[i]+i);j++)b[j]++;
int ans=0;
for(int i=1;i<=n;i++)
if(a[i]>b[i])ans+=(a[i]-b[i]-1);
else b[i+1]+=(b[i]-a[i]+1);
cout<<ans<<endl;
}
signed main()
{
cin>>T;
while(T--)
solve();
}
J. RPD and Rap Sheet (Easy Version)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k;
void solve()
{
cin>>n>>k;
cout<<0<<endl;
int ans=1;
int t;cin>>t;
while(t==0)
{
cout<<(ans^(ans-1))<<endl;
cin>>t;
ans++;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin>>T;
while(T--)
solve();
}