- D题 Move
思路:一直以为会是单调的,但是实则没有单调型,有些地方是平稳的。。。。
暴力直接可以过,用map去模拟搬箱子的过程:
#include<bits/stdc++.h>
#define LL long long
#define ms0(x) memset(x,0,sizeof(x))
#define ms-1(x) memset(x,-1,sizeof(x))
const int maxn=1e3+3;
using namespace std;
int v[maxn];
map<int,int> mp;map<int,int> ori;
void init(int &n) //把各个物品的情况放到map容器里
{
ori.clear();
for(int j=0;j<n;j++)
{
if(ori.find(v[j])==ori.end())//map容器里键值就是物品的volume,second是其相同volume的数量
{
ori[v[j]]=1;
}
else
ori[v[j]]++;
}
return;
}
int n,k;
int solve(int box_size)
{
mp=ori;//循环赋值 应该快点
for(int j=1;j<=k;j++)
{
int tmp_size=box_size;
while(mp.size()!=0)
{
auto it =mp.upper_bound(tmp_size);
if(it==mp.begin())
{
break;
}
else
{
it--;
it->second-=1;
tmp_size-=it->first;
if(it->second<=0)
mp.erase(it);
}
}
}
if(mp.empty()==0)
return 0;
return 1;
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;int cas=0;
while(t--)
{
cin>>n>>k;int max_num=0;int sum=0;
for(int j=0;j<n;j++)
{
cin>>v[j];
max_num=max(max_num,v[j]);
sum+=v[j];
}
sort(v,v+n);
init(n);
int l=max(sum/k,max_num);//关键是这里的临界值,肯定是所有物品中最大的或者总volume除箱子数
int r=sum/k+max_num;
while(!solve(l))
{
l++;
}
cout<<"Case #"<<++cas<<": "<<l<<endl;
}
return 0;
}
不敢相信如此暴力简单。。。
B题:Shorten IPv6 Address
题目链接:https://ac.nowcoder.com/acm/contest/886/B
关键还是看题,题目看着看着漏掉要字符串最短的,再要字典序最小的。。。。
好好研究了人家最短的代码:
其思路其实关键就在,多个长度一样且最大的0序列时,如果只有一头一尾,取尾部变为双冒号,其他情况,尽可能让中间的且最后面的变双冒号。
#include<iostream>
#include<cstdio>
using namespace std;
int a[20];
int main(){
int T,x;
cin>>T;
for(int ceisi=1;ceisi<=T;ceisi++){
int f=0,l=0,n0=0;
for(int i=1;i<=8;i++){
a[i]=0;
for(int j=1;j<=16;j++){
scanf("%1d",&x);
a[i]=a[i]*2+x;
}
if(a[i]==0)n0++;
else {
if(n0>l&&n0>1){
f=i-n0;
l=n0;
}
else
{
if(n0==l&&n0>1)
{
f=i-n0;
l=n0;
}
}
n0=0;
}
if(i==8&&n0>1){
if(n0>l||(n0==l&&f==1)){
f=i-n0+1;//这里有点厉害,如果是最后变成双冒号f变成后一位。
l=n0;
}
}
}
printf("Case #%d: ",ceisi);
if(f==1)printf(":");
for(int i=1; i<=8; i++) {
if(i==f) {
printf(":");
i+=l;
}
if(i>8)puts("");
else printf("%x%c",a[i],":\n"[i==8]);
}
}
return 0;
}
G题:全排列加求星期几,求星期几用基姆拉尔森计算公式即可。
一开始本来想预处理所有1600年到9999年的日期,但是估计会超时。
题目链接:https://ac.nowcoder.com/acm/contest/886/G
找对应规律,全排列一个个试吧。
重点:要去重,资料:https://www.cnblogs.com/wangkundentisy/p/9033782.html
公式内容:https://wenku.baidu.com/view/6b4c55b31b37f111f18583d049649b6648d7097b.html
#include<bits/stdc++.h>
#define LL long long
#define ms0(x) memset(x,0,sizeof(x))
#define ms-1(x) memset(x,-1,sizeof(x))
using namespace std;
const int maxn=1e5+6;
string s[maxn];
int a[10]; //用来全排列的数组
int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
inline bool check(int y,int m,int d)
{
if(y<1600)return false;
if(m==0||m>12)return false;
int tmp=days[m];
if(m==2&&((y%4==0&&y%100!=0)||y%400==0))tmp=29;//这里细节括号不能少了
if(d<=0||d>tmp)return false;
//-----基姆拉尔森计算公式-----//
if(m<=2)
{
m+=12;
y--;
}
int day=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;//公式
return day==4;
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;int cas=1;int n;
while(t--)
{
cout<<"Case #"<<cas++<<": ";
cin>>n;
for(int j=0;j<10;j++)
a[j]=j;
for(int j=0;j<n;j++)
cin>>s[j];
sort(s,s+n);
int realn=unique(s,s+n)-s; //注意 要去重
bool flag=false;//判断有没有合法的密码对应规则
do{
bool isok=true;
for(int j=0;j<realn;j++)
{
int y=a[s[j][0]-'A']*1000+a[s[j][1]-'A']*100+a[s[j][2]-'A']*10+a[s[j][3]-'A'];
int m=a[s[j][5]-'A']*10+a[s[j][6]-'A'];
int d=a[s[j][8]-'A']*10+a[s[j][9]-'A'];
if(!check(y,m,d))
{
isok=0;
break;
}
}
if(isok==1)
{
flag=true;
for(int i=0;i<10;i++)
cout<<a[i];
cout<<endl;
break;
}
}while(next_permutation(a,a+10));
if(flag==0)cout<<"Impossible\n";
}
return 0;
}