第五届辽宁省大学生程序设计竞赛(大连)题解
Prepared by Beater , Core_65536
A.爱上字典
思路:
不断读入字符串,将大写字母全转换成小写字母,特殊字符忽略,将每个字符串存入map中,读到数字就退出。
读入已经会的n个单词,如果这个单词在map中则将这个单词从map中删去,答案就是map中剩余的字符串个数
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
void solve()
{
map<string,int>mp;
string s;
while(1)
{
cin>>s;
//mp[s]++;
int f=0;
for(auto i:s)
if(isdigit(i))
{
f=1;
break;
}
if(f) break;
string t;
for(auto i:s)
if(isupper(i)) t+=tolower(i);
else if(islower(i)) t+=i;
mp[t]++;
}
int t=0;
for(auto i:s) t=t*10+(i-'0');
while(t--)
{
string s;
cin>>s;
if(mp.count(s)) mp.erase(s);
}
cout<<mp.size()<<"\n";
}
int main (){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
B.比分幻术
思路:
读入字符串,交换一下两个比分,输出
题目还没看,队友样例都没测就交了(
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
void solve(){
string s; cin>>s;
swap(s[0],s[2]);
cout<<s<<endl;
}
int main (){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
C.插排串联
思路:
dfs求出每个插座需要承载的功率,将所有插座的承载功率排个序,再将每个插排的限制功率排个序,按顺序依次匹配,若无法承载功率则输出"NO"(包括根节点)否则输出"YES"
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define int long long
vector<int>g[100010];
int n,f[100010],a[100010];
int sum[100010];
vector<int>vt;
void dfs(int u,int fa)
{
if(g[u].size()==1&&u!=0)
{
vt.push_back(u);
sum[u]=a[u];
return ;
}
sum[u]=0;
for(auto v:g[u])
{
if(v==fa) continue;
dfs(v,u);
sum[u]+=sum[v];
}
}
int vis[100010];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
vis[i]=0;
cin>>f[i]>>a[i];
g[f[i]].push_back(i);
g[i].push_back(f[i]);
}
dfs(0,-1);
for(auto i:vt) vis[i]=1;
vector<int>rs;
vector<int>ra;
for(int i=1;i<=n;i++) if(!vis[i]) rs.push_back(sum[i]);
for(int i=1;i<=n;i++) if(!vis[i]) ra.push_back(a[i]);
sort(rs.begin(),rs.end());
sort(ra.begin(),ra.end());
for(int i=0;i<rs.size();i++)
if(rs[i]>ra[i])
{
cout<<"NO\n";
return ;
}
int s=0;
for(auto i:g[0])
{
s+=sum[i];
}
if(s>2200)
{
cout<<"NO\n";
return ;
}
cout<<"YES\n";
}
signed main ()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
D.都市叠高
思路:
诈骗题,看着像计算几何实际就是一个dp
每一次叠楼层增长的高度一定是凸包中某两个点的线段距离,考虑到n为5000,直接暴力\(n^2\)求出所有点两两之间的距离,当选择两个点\((j,i)\)后,这两个点之间的所有点都将失效,因此状态应该从第一个点j前面转移而来,状态转移方程:
$ dp_i =dp_{j-1} + dis(j,i) $
时间复杂度\(O(n^2)\)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
ll n,x[6010],y[6010];
long double dis(int i,int j)
{
return sqrtl(powl(x[i]-x[j],2.0)+powl(y[i]-y[j],2.0));
}
long double dp[6010];
void solve()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld %lld",&x[i],&y[i]);
dp[0]=0;
for(int i=1;i<=n;i++)
{
dp[i]=dp[i-1];
for(int j=1;j<i;j++)
{
long double d=dis(i,j);
dp[i]=max(dp[i],dp[j-1]+d);
}
}
long double ans1=0;
for(int i=1;i<=n;i++) ans1=max(ans1,dp[i]);
printf("%.20llf\n",ans1);
}
int main ()
{
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
E.俄式简餐
思路:
若n和m有一边可以被4整除,则用俄罗斯方块2填满
| 1 | 1 | 1 | 1 |
|---|
若n和m有一边减去6后能被4整除,另一条边能被2整除
则这样填满
| 1 | 1 | 1 | 2 | 2 | 2 | 4 | 4 | 4 | 4 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 3 | 3 | 3 | 3 | 2 | 5 | 5 | 5 | 5 |
首先由题得,当\(nm/4\)不整除时必定无解。
然后发现当n或m整除4时可以轻松构造。
所以此时还剩下:nm整除4 且 nm都不为4倍数 的情况。
于是我们知道,这种情况即n、m至少有一个是2的倍数。
于是从最小的开始考虑,便构造出了\(6*2\)的情况,接着发现可以递推得出\((6+4k)*2\)的构造方式。
又考虑到\(n*2\)的构造方式只对\((6+4k)*2\)或\(4*2\)有解。
所以我们知道,以上即为所有情况。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
void solve(){
int n,m;
cin>>n>>m;
vector<vector<int > > ans(n+1,vector<int > (m+1));
if(m%4==0){
int cnt=1;
for(int i=1;i<=n;i++)
{
int count=0;
for(int j=1;j<=m;j++)
{
ans[i][j]=cnt;
count++;
if(count==4){
count=0;
cnt++;
}
}
}
}else if(n%4==0){
int cnt=1;
for(int j=1;j<=m;j++){
int count=0;
for(int i=1;i<=n;i++){
ans[i][j]=cnt;
count++;
if(count==4){
count=0;
cnt++;
}
}
}
}else if(m>=6&&(m-6)%4==0&&n%2==0){
int cnt=1;
auto sd=[&](int x,int y){
for(int j=y;j<y+3;j++){
ans[x+1][j]=cnt;
}
ans[x][y]=cnt;
cnt++;
for(int j=y+3;j<y+3+3;j++){
ans[x+1][j]=cnt;
}
ans[x][y+5]=cnt;
cnt++;
for(int j=y+1;j<y+1+4;j++){
ans[x][j]=cnt;
}
cnt++;
};
for(int i=1;i<=n;i+=2){
sd(i,1);
}
for(int i=1;i<=n;i++){
int count=0;
for(int j=7;j<=m;j++){
ans[i][j]=cnt;
count++;
if(count==4){
count=0;
cnt++;
}
}
}
}else if(n>=6&&(n-6)%4==0&&m%2==0){
int cnt=1;
auto sd1=[&](int x,int y){
for(int i=x;i<x+3;i++){
ans[i][y]=cnt;
}
ans[x][y+1]=cnt;
cnt++;
for(int i=x+3;i<x+3+3;i++){
ans[i][y]=cnt;
}
ans[x+5][y+1]=cnt;
cnt++;
for(int i=x+1;i<x+1+4;i++){
ans[i][y+1]=cnt;
}
cnt++;
};
for(int j=1;j<=m;j+=2){
sd1(1,j);
}
for(int j=1;j<=m;j++){
int count=0;
for(int i=7;i<=n;i++){
ans[i][j]=cnt;
count++;
if(count==4){
count=0;
cnt++;
}
}
}
}else{
cout<<"NO"<<endl;
return ;
}
cout<<"YES"<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
}
int main (){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
G.顾影自怜
思路:
二分加st表。
对于一个元素x,找出右边界使得这个区间内最大值为x,找出元素x出现k次时的下标,这个区间就是贡献。例如:3 3 2 3 1 2 4,当k为3时,对于第一个元素3下标为1,第k个3下标为4,右边界为6,那么这一部分贡献就是6-4+1=3(这个只是单纯的加1),即(3 3 2 3)、(3 3 2 3 1)、(3 3 2 3 1 2)都可以为答案。接下来统计左边的贡献,向左找左边界,使该元素左边的元素都比他小,这样不会造成重复统计,例如3 1 2 3 3 2 3 1 2 4,(3 3 2 3)、(2 3 3 2 3)、(1 2 3 3 2 3)都可以为答案。我们将左右两边的贡献相乘就是这个下标的元素的总贡献,将所有元素的贡献相加即可
时间复杂度\(O(nlog)\)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
typedef unsigned long long ull;
const int MAXN=2e6+7;
int Log2[MAXN],Min[MAXN][21],Max[MAXN][21];
void solve(){
int n,k;
cin>>n>>k;
int a[n+1];
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;++i){
Min[i][0]=a[i];
Max[i][0]=a[i];
}
for(int i=2;i<=n;++i){
Log2[i]=Log2[i/2]+1;
}
for(int i=1;i<=20;++i){
for(int j=1;j+(1<<i)-1<=n;++j){
Min[j][i]=min(Min[j][i-1],Min[j+(1<<(i-1))][i-1]);
Max[j][i]=max(Max[j][i-1],Max[j+(1<<(i-1))][i-1]);
}
}
vector<vector<int > > idx(n+1);
vector<int > vis(n+1);
for(int i=1;i<=n;++i){
idx[a[i]].push_back(i);
vis[i]=idx[a[i]].size()-1;
}
auto check=[&](int l,int r){
int s=Log2[r-l+1];
int ma=max(Max[l][s],Max[r-(1<<s)+1][s]);
if(ma<=a[l]){
return 1;
}else{
return 0;
}
};
auto check1=[&](int l,int r){
int s=Log2[r-l+1];
int ma=max(Max[l][s],Max[r-(1<<s)+1][s]);
if(ma<a[r+1]){
return 1;
}else{
return 0;
}
};
ull ans=0;
for(int i=1;i<=n;i++){
if(vis[i]+k-1>=idx[a[i]].size()){
continue;
}
int left=i,right=n+1;
while(left<right){
int mid=(left+right)/2;
if(check(i,mid)==1){
left=mid+1;
}else{
right=mid;
}
}
int rico=left-1;
int cnt=idx[a[i]][vis[i]+k-1];
int leco=i;
if(i>1){
left=1,right=i;
while(left<right){
int mid=(left+right)/2;
if(check1(mid,i-1)==1){
right=mid;
}else{
left=mid+1;
}
}
if(left>=1&&left<i){
leco=left;
}
}
if(cnt<=rico){
ll st1=(rico-cnt+1);
ll st2=(i-leco+1);
ans+=st1*st2;
}
}
cout<<ans<<endl;
}
int main (){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
J.结课风云
思路:
若该学生已经及格则跳过,若该学生要挂科了,则给他加平时分(这里有个上限),如果捞起来了则统计答案
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
void solve(){
int n;
cin>>n;
int a,b,c;
cin>>a>>b>>c;
int x[n+1],y[n+1];
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i];
}
int d;
cin>>d;
int ans=0;
for(int i=1;i<=n;i++){
int st=x[i]+y[i];
if(st>=c){
continue;
}
st+=min(d,a-x[i]);
if(st>=c){
ans++;
}
}
cout<<ans<<endl;
}
int main (){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
L.龙之研习
思路:
二分答案,减去闰年的天数
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define int long long
int n,k;
bool ck(__int128 x)
{
__int128 sum=0;
for(__int128 i=4;i<=x;)
{
sum+=x/i-x/(25*i);
i*=100;
}
return x-sum>=k;
}
void solve()
{
cin>>k;
k+=1533;
int l=1;
int r=2e18;
while(l<=r)
{
int mid=l+r>>1;
if(ck(mid)) r=mid-1;
else l=mid+1;
}
cout<<l<<"\n";
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
M.盲盒谜题
思路:
超级大模拟
代码:
/*
Problem: 2024 CCPC Liaoning Provincial Contest/M
Author: Core_65536
Last_Update: 2024-11-5
*/
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
const pair<int,int> loc[11] = { // 每一号宫格的坐标
{0,0}, {2,2},{1,1},{1,2},
{1,3},{2,1},{2,3},
{3,1},{3,2},{3,3}
};
map<pair<int,int>,int> col = { // 每个坐标的宫格号
{{2,2},1}, {{1,1},2}, {{1,2},3},
{{1,3},4}, {{2,1},5}, {{2,3},6},
{{3,1},7}, {{3,2},8}, {{3,3},9}
};
const vector<vector<pair<int ,int>>> dir = { // 已经排好序的8种情况的比较坐标
{{1,1},{2,2},{3,3}}, //1 2 9
{{1,2},{2,2},{3,2}}, //1 3 8
{{1,3},{2,2},{3,1}}, //1 4 7
{{2,1},{2,2},{2,3}}, //1 5 6
{{1,1},{1,2},{1,3}}, //2 3 4
{{1,1},{2,1},{3,1}}, //2 5 7
{{1,3},{2,3},{3,3}}, //4 6 9
{{3,1},{3,2},{3,3}} //7 8 9
};
void solve(){
// t:luck
int n,m,k,t; cin>>n>>m>>k>>t;
queue<int> a; // 沸羊羊的盲盒队列
queue<int> got; // 美羊羊获得的盲盒队列
int chess[4][4]; memset(chess,-1,sizeof(chess)); // 棋盘
map<int,int> ans; // 每个盲盒获得的数量
int res = 0; // 缺少的盲盒数量
for(int i=1;i<=k;i++){ // 输入沸羊羊的盲盒队列
int x; cin>>x;
a.push(x);
}
for(int i=0;i<n;i++){ // 初始化美羊羊的盲盒队列
got.push(a.front());
a.pop();
}
while(1){ //游戏循环
//Step 1 放置盲盒
int ok = 0,DidSth = 0; // ok:是否拆出隐藏款 DidSth:是否有操作
for(int i=1;i<=9&&(!got.empty());i++){ // 遍历每一个宫格
if(chess[loc[i].first][loc[i].second] != -1){ // 如果宫格已经有盲盒则跳过
continue;
}
DidSth = 1; // 有操作
int x = got.front(); got.pop(); // 美羊羊取出一个盲盒
chess[loc[i].first][loc[i].second] = x; // 放入宫格
if(x == t){ // 如果是幸运款
if(!a.empty()){ // 如果沸羊羊还有盲盒
got.push(a.front()); // 奖励一个盲盒
a.pop();
}else{ // 沸羊羊没有盲盒
res ++; // 缺少的盲盒数量+1
}
}else if(x == 0){ // 如果是隐藏款
if(!a.empty()){
got.push(a.front());
a.pop();
}else{
res ++;
}
ans[x] ++ ; // 更新答案
chess[loc[i].first][loc[i].second] = -1;
ok = 1;
break;
}
}
if(ok){ // 如果拆出隐藏款则跳过后面的步骤
continue;
}
//Step 2 判断是否9个盲盒均不同
unordered_map<int ,int> count;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
if(chess[i][j] != -1) // 排除空格
count[chess[i][j]] ++ ;
if(count.size() == 9){ // 9个盲盒均不同
DidSth = 1;
ans[chess[loc[1].first][loc[1].second]] ++; // 更新答案
chess[loc[1].first][loc[1].second] = -1;
}
//Step 3 按顺序检查8种三连珠情况
int UseSpeFlag = 0; // 是否利用到特殊格
vector<vector<int>> process; // 存储有几种三连珠情况 & 每一种情况的三个盲盒的宫格号
for(int i=0;i<8;i++){
int x1[3],y1[3];
for(int j=0;j<3;j++){ // 存入当前需要比较的坐标
x1[j] = dir[i][j].first;
y1[j] = dir[i][j].second;
}
// 比较三个盲盒是否相同 & 排除空格
if(chess[x1[0]][y1[0]]==chess[x1[1]][y1[1]]&&chess[x1[1]][y1[1]]==chess[x1[2]][y1[2]]&&chess[x1[0]][y1[0]]!=-1){
DidSth = 1;
vector<int> cnt;
for(int j=0;j<3;j++){
cnt.push_back(col[{x1[j],y1[j]}]); // 存入宫格号
}
process.push_back(cnt); // 存入当前三连珠情况
}
}
//Start Process
for(auto i:process){ // 遍历每一种三连珠情况
int x1[3],y1[3];
for(int j=0;j<3;j++){ // 存入当前需要处理的坐标
x1[j] = loc[i[j]].first;
y1[j] = loc[i[j]].second;
}
// 排除已经处理过变成空格的宫格
if(chess[x1[0]][y1[0]]!=-1&&chess[x1[1]][y1[1]]!=-1&&chess[x1[2]][y1[2]]!=-1){
for(int j=0;j<5;j++){ // 发放奖励盲盒
if(!a.empty()){
got.push(a.front());
a.pop();
}else{
res ++;
}
}
for(int j=0;j<3;j++){ // 遍历三连珠的三个盲盒
if(i[j] == 1){ // 如果是特殊格
UseSpeFlag = 1;
continue;
}else{ // 不是特殊格
ans[chess[x1[j]][y1[j]]] ++; // 更新答案
chess[x1[j]][y1[j]] = -1;
}
}
}
}
//Step 4 顺序检查任意两种盲盒是否相同
for(int i=1;i<=9;i++){
for(int j=i;j<=9;j++){
if(j <= i) continue; // 遍历宫格号以做到顺序遍历
int x1 = loc[i].first, y1 = loc[i].second;
int x2 = loc[j].first, y2 = loc[j].second;
// 如果两个盲盒相同 & 不是空格
if(chess[x1][y1] == chess[x2][y2] && chess[x1][y1] != -1){
DidSth = 1;
if(i == 1){ // 如果第一个利用到特殊格
UseSpeFlag = 1;
if(!a.empty()){
got.push(a.front());
a.pop();
}else{
res ++;
}
ans[chess[x2][y2]] ++; // 更新答案
chess[x2][y2] = -1;
continue;
}
if(j == 1){ // 如果第二个利用到特殊格
UseSpeFlag = 1;
if(!a.empty()){
got.push(a.front());
a.pop();
}else{
res ++;
}
ans[chess[x1][y1]] ++; // 更新答案
chess[x1][y1] = -1;
continue;
}
// 如果没利用到特殊格
if(!a.empty()){
got.push(a.front());
a.pop();
}else{
res ++;
}
ans[chess[x1][y1]] += 2; // 更新答案
chess[x1][y1] = chess[x2][y2] = -1;
}
}
}
//Step 5 判断是否利用到特殊格
if(UseSpeFlag == 1){
DidSth = 1;
ans[chess[2][2]] ++; // 更新答案
chess[2][2] = -1;
}
//Step 6 如果没有操作游戏结束
if(!DidSth){
break;
}
int Judge0Flag = 0; // 判断是否清台
for(int i = 1 ;i <= 9 ; i++){
if(chess[loc[i].first][loc[i].second] == -1)
Judge0Flag ++;
}
if(Judge0Flag == 9){ // 如果清台
for(int i=0;i<10;i++){ // 发放奖励盲盒
if(!a.empty()){
got.push(a.front());
a.pop();
}else{
res ++;
}
}
}
}
// 游戏结束, 清理棋盘
for(int i=1;i<=9;i++){
if(chess[loc[i].first][loc[i].second] != -1){
ans[chess[loc[i].first][loc[i].second]] ++;
chess[loc[i].first][loc[i].second] = -1;
}
}
for(int i = 0;i <= m;i ++){ // 输出每一种盲盒获得的数量
cout<<ans[i]<<" \n"[i==m];
}
if(res != 0){ // 输出缺少的盲盒数量
cout<<"Unhappy! "<<res<<endl;
}
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t=1; // cin>>t;
while(t--){
solve();
}
return 0;
}

浙公网安备 33010602011771号