AtCoder Beginner Contest 319
ABC319 A - Legendary Players
代码(签到题)
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
char s[21];
scanf("%s",s+1);
switch (s[1]){
case 't':{
printf("3858");
break;
}
case 'k':{
printf("3679");
break;
}
case 'B':{
printf("3658");
break;
}
case 'U':{
printf("3648");
break;
}
case 'a':{
printf("3638");
break;
}
case 'S':{
printf("3630");
break;
}
case 'e':{
printf("3613");
break;
}
case 'm':{
printf("3555");
break;
}
case 'n':{
printf("3516");
break;
}
case 's':{
printf("3481");
break;
}
}
return 0;
}
ABC319 B - Measure
代码(签到题)
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
int n=iut();
printf("1");
for (int i=1;i<=n;++i){
int flag=1;
for (int j=1;j<=9;++j)
if (i*j%n==0){
printf("%d",j);
flag=0;
break;
}
if (flag) printf("-");
}
return 0;
}
ABC319 C - False Hope
分析
比赛时题目没看懂,看懂了就很简单,穷举观察顺序即可
代码
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
int a[9],rk[9],ans;
bool check(int x,int y,int z){
if (rk[x]<rk[z]&&rk[y]<rk[z]&&a[x]==a[y]) return 0;
if (rk[x]<rk[y]&&rk[z]<rk[y]&&a[x]==a[z]) return 0;
if (rk[y]<rk[x]&&rk[z]<rk[x]&&a[y]==a[z]) return 0;
return 1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for (int i=0;i<3;++i)
for (int j=0;j<3;++j) cin>>a[i*3+j];
for (int i=0;i<9;++i) rk[i]=i;
do{
int flag=check(0,1,2)&check(6,7,8)&check(0,3,6)&check(2,5,8);
for (int i=0;i<4;++i) flag&=check(4,i,8-i);
ans+=flag;
}while (next_permutation(rk,rk+9));
cout<<fixed<<setprecision(10)<<ans/362880.0;
return 0;
}
ABC319 D - Minimum Width
分析
二分答案,判定是否能装入不超过 \(m\) 行
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int n,a[200011],m; long long l,r;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
bool check(long long mid){
int duan=1; long long sum=a[1]+1;
for (int i=2;i<=n;++i)
if (sum+a[i]>mid) ++duan,sum=a[i]+1;
else sum+=a[i]+1;
return duan<=m;
}
int main(){
n=iut(),m=iut();
for (int i=1;i<=n;++i){
a[i]=iut(),r+=a[i]+1;
l=max(l,(long long)a[i]);
}
while (l<r){
long long mid=(l+r)>>1;
if (check(mid)) r=mid;
else l=mid+1;
}
printf("%lld",l);
return 0;
}
ABC319 E - Bus Stops
分析
实际的出发时刻只有 \(lcm(1,\dots,8)=840\) 种情况,直接分类讨论即可
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=100011,mod=840;
typedef long long lll;
int n,p[N],t[N],X,Y; long long sum,dp[mod];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
int main(){
n=iut(),X=iut(),Y=iut(),sum=X+Y;
for (int i=1;i<n;++i) p[i]=iut(),t[i]=iut(),sum+=t[i];
for (int j=0;j<mod;++j){
int x=j;
for (int i=1;i<n;++i)
if (x%p[i]==0) x=(x+t[i])%mod;
else dp[j]+=p[i]-x%p[i],x=(x+p[i]-x%p[i]+t[i])%mod;
}
for (int Q=iut();Q;--Q,putchar(10)){
int x=iut();
print(dp[(x+X)%mod]+x+sum);
}
return 0;
}
ABC319 F - Fighter Takahashi
分析
七十个点只有一个没过调了一个小时QAQ
由于药的个数很少,设 \(dp[S]\) 表示选取药的状态为 \(S\) 时所能获得的最大力量
那么 \(dp[S|2^j]=\max\{dp[S]\times a_j\}\),显然这是不够的,
每次dp转移好一个状态后,应用贪心不断扩展新的位置,除非该药还未选择或无法到达该位置
显然先加再乘。加的部分可以用布尔数组存下哪些位置未被访问
时间复杂度 \(O(n2^m\log n)\)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <queue>
#include <bitset>
using namespace std;
const int N=523; long long dp[N<<1];
priority_queue<pair<int,int> >q; bitset<N>v[N<<1];
int n,lim[N],nxt[N],mx,as[N],a[N],m,b[N],rk[N],B[N];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
int main(){
n=iut(),lim[1]=mx=1;
for (int i=2;i<=n;++i){
int x=iut();
nxt[i]=as[x],as[x]=i,x=iut();
lim[i]=iut(),a[i]=iut();
if (x==2) rk[i]=m,b[m++]=i;
else mx=max(mx,lim[i]);
}
dp[0]=1;
for (int S=0;S<(1<<m);++S)
if (dp[S]){
q.push(make_pair(-1,1)),B[0]=0;
while (!q.empty()){
int x=q.top().second; q.pop();
if (lim[x]||((S>>rk[x])&1)){
if (lim[x]>dp[S]){
while (!q.empty()) q.pop();
break;
}
if (!v[S][x]&&lim[x]) dp[S]+=a[x],v[S][x]=1;
for (int y=as[x];y;y=nxt[y])
q.push(make_pair(-lim[y],y));
}else B[++B[0]]=rk[x];
}
if (dp[S]>=mx) return !printf("Yes");
for (int i=1;i<=B[0];++i)
if (dp[S|(1<<B[i])]<dp[S]*a[b[B[i]]]){
dp[S|(1<<B[i])]=dp[S]*a[b[B[i]]],v[S|(1<<B[i])]=v[S];
if (dp[S|(1<<B[i])]>=mx) return !printf("Yes");
}
}
return !printf("No");
}
ABC319 G - Counting Shortest Paths
分析
由于边权均为一,不妨将图分层,可以直接从未访问过的点中选择,复杂度为 \(O(n+m)\)
分层后其实到每个点的最短路只可能从上一层转移而来,容斥一下即可
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
using namespace std;
const int N=200011,mod=998244353;
vector<int>G[N]; queue<int>q; map<int,bool>uk[N];
int n,m,dep[N],dp[N],v[N],pre[N],nxt[N],rk[N],L,R,sum;
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void Mo(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
bool cmp(int x,int y){return dep[x]<dep[y];}
int main(){
n=iut(),m=iut();
for (int i=1;i<=m;++i){
int x=iut(),y=iut();
G[x].push_back(y),uk[x][y]=1;
G[y].push_back(x),uk[y][x]=1;
}
for (int i=1;i<=n;++i) nxt[i]=i+1,sort(G[i].begin(),G[i].end());
for (int i=2;i<=n+1;++i) pre[i]=i-1,dep[i]=n+1;
q.push(1);
while (!q.empty()){
int x=q.front(); q.pop();
for (int y=nxt[1];y!=n+1;y=nxt[y])
if (!uk[x][y]){
dep[y]=dep[x]+1,q.push(y);
pre[nxt[y]]=pre[y];
nxt[pre[y]]=nxt[y];
}
}
if (dep[n]==n+1) return !printf("-1");
for (int i=1;i<=n;++i) rk[i]=i;
sort(rk+1,rk+1+n,cmp),L=R=1,dp[1]=1;
for (int l=2,r;l<=n;l=r+1){
sum=0;
for (int i=L;i<=R;++i) v[rk[i]]=1,Mo(sum,dp[rk[i]]);
for (r=l;r<=n&&dep[rk[r]]==dep[rk[l]];++r); --r;
for (int i=l;i<=r;++i){
int Sum=sum,siz=G[rk[i]].size();
for (int j=0;j<siz;++j)
if (v[G[rk[i]][j]]) Mo(Sum,mod-dp[G[rk[i]][j]]);
dp[rk[i]]=Sum;
if (rk[i]==n) return !printf("%d",dp[n]);
}
for (int i=L;i<=R;++i) v[rk[i]]=0;
L=l,R=r;
}
return 0;
}