The 45th ICPC Asia East Continent Final Contest部分题解(F,L,K,B)
F. Rooks
题意:
给定庞教授的 \(n_1\) 个车和寿教授的 \(n_2\) 个车(均在二维平面整数坐标上,位置互不重复),判断每个车是否被攻击。攻击条件:两车分属不同棋手,横坐标或纵坐标相同,且两点连线间无其他车。
思路:
用map模拟每行每列,二分查找一下。
代码
点击查看代码
void solve() {
int n1,n2;
cin>>n1>>n2;
vector<PII>q1,q2;
vector<int>ans1(n1,0),ans2(n2,0);
for(int i=1;i<=n1;i++){
int x,y;
cin>>x>>y;
q1.push_back({x,y});
}
for(int i=1;i<=n2;i++){
int x,y;
cin>>x>>y;
q2.push_back({x,y});
}
map<int,vector<PIII>>qx,qy;
for(int i=0;i<q1.size();i++){
qx[q1[i].first].push_back({q1[i].second,{1,i}});
qy[q1[i].second].push_back({q1[i].first,{1,i}});
}
for(int i=0;i<q2.size();i++){
qx[q2[i].first].push_back({q2[i].second,{2,i}});
qy[q2[i].second].push_back({q2[i].first,{2,i}});
}
for(auto &[x,y]:qx){
sort(y.begin(),y.end());
for(int i=0;i<y.size();i++){
if(i){
if(y[i-1].second.first!=y[i].second.first){
if(y[i].second.first==1){
ans1[y[i].second.second]=1;
}else{
ans2[y[i].second.second]=1;
}
}
}
if(i+1<y.size()){
if(y[i+1].second.first!=y[i].second.first){
if(y[i].second.first==1){
ans1[y[i].second.second]=1;
}else{
ans2[y[i].second.second]=1;
}
}
}
}
}
for(auto &[x,y]:qy){
sort(y.begin(),y.end());
for(int i=0;i<y.size();i++){
if(i){
if(y[i-1].second.first!=y[i].second.first){
if(y[i].second.first==1){
ans1[y[i].second.second]=1;
}else{
ans2[y[i].second.second]=1;
}
}
}
if(i+1<y.size()){
if(y[i+1].second.first!=y[i].second.first){
if(y[i].second.first==1){
ans1[y[i].second.second]=1;
}else{
ans2[y[i].second.second]=1;
}
}
}
}
}
for(int i=0;i<n1;i++){
cout<<ans1[i];
}cout<<endl;
for(int i=0;i<n2;i++){
cout<<ans2[i];
}cout<<endl;
}
L. Square
题意:给定整数序列 \(a_1,a_2,...,a_n\),需构造正整数序列 \(t_1,t_2,...,t_n\),满足对每个 \(1≤i<n\),\(a_i×t_i×a_{i+1}×t_{i+1}\) 是完全平方数,且 \(t_1×t_2×...×t_n\) 最小,输出该最小值对 \(10^9+7\) 取模的结果。
思路:
分别对每个质因数分开讨论。
不妨令 \(a_i=p^{k_i}\),如要满足条件,则所有 \(k_i\) 的奇偶性要相同,否则存在 \(j\) 满足 \(a_j×a_{j+1}=p^{k_j+k_{j+1}}\),\(k_j+k_{j+1}\) 为奇数,与条件相悖。
则对每个质因数,选择全奇数和全偶数代价更小的那个,累乘得到答案。
代码
点击查看代码
int minp[N];
int prime[N];
int cnt;
void sieve() {
cnt=0;
for (int i = 2; i < N; ++i) {
if (minp[i] == 0) {
minp[i] = i;
prime[++cnt]=i;
}
for (int j=1;j<=cnt;j++) {
int p=prime[j];
if (p * i >= N) break;
minp[p * i] = p;
if (i % p == 0) break;
}
}
}
int qpow(int a, int b) {
int r = 1;
while (b) {
if (b & 1) r = r * a % mod;
a = a * a % mod;
b >>= 1;
}
return r;
}
vector<int>g[N];
int a[N];
void solve() {
sieve();
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
while(a[i]>1){
int p=minp[a[i]];
int s=0;
while(a[i]%p==0){
a[i]/=p;
s++;
}
if(s%2){
int d=lower_bound(prime+1,prime+1+cnt,p)-prime;
g[d].push_back(i);
}
}
}
int ans=1;
for(int i=1;i<=cnt;i++){
if(g[i].size()){
ans*=qpow(prime[i],min((int)g[i].size(),n-(int)g[i].size()));
ans%=mod;
}
}
cout<<ans<<endl;
}
K. Allin
题意:
两个玩家,每个玩家 \(2\) 张牌,加上公共牌 \(5\) 张,每个玩家用自己的 \(2\) 张牌和公共牌 \(5\) 张选出 \(5\) 张,组出最好的牌型,比较牌型大小。从小到大分别为高牌,一对,两对,三条,顺子,同花,葫芦,四条,同花顺,皇家同花顺。
给定 Wolf Chicken 的两张底牌和三张翻牌,判断在所有可能的剩余两张公共牌及所有可能的对手底牌组合下,Wolf Chicken 是否必定获胜。若是,输出 "allin";否则输出 "check"。
思路:
这道题主要是分类讨论加模拟。
Wolf Chicken 的牌是固定的,所以只要对每种牌型进行分类讨论即可。
由于对面有 \(4\) 张未知牌,不难证明对面的牌型至少为同花顺。皇家同花顺也是同花顺。我们只需考虑 Wolf Chicken 的牌型为同花顺的情况即可。
首先判断出 Wolf Chicken 是哪个同花顺,然后枚举比他大的同花顺,判断对面是否能组出即可。
代码
点击查看代码
string a[N],b[N];
int f(string s){
if(s[0]<='9'&&s[0]>='2'){
return s[0]-'0';
}else{
if(s[0]=='A'){
return 14;
}else if(s[0]=='T'){
return 10;
}else if(s[0]=='J'){
return 11;
}else if(s[0]=='Q'){
return 12;
}else if(s[0]=='K'){
return 13;
}
}
}
bool cmp(string x,string y){
return f(x)<f(y);
}
string str="0123456789TJQKA";
void solve() {
for(int i=1;i<=5;i++){
cin>>a[i];
b[i]=a[i];
}
for(int i=1;i<=4;i++){
if(a[i][1]!=a[i+1][1]){
cout<<"check\n";
return;
}
}
sort(a+1,a+1+5,cmp);
// for(int i=1;i<=5;i++){
// cout<<a[i]<<' ';
// }cout<<endl;
int st=f(a[1]);
int flag=1;
for(int i=2;i<=5;i++){
if(f(a[i])==st+i-1){
}else{
flag=0;
}
}
if(flag){
int fl=0;
for(int i=st+1;i<=10;i++){
int f1=0,f2=1;
if(f(b[1])>=i&&f(b[1])<=i+4){
f2=0;
}
if(f(b[2])>=i&&f(b[2])<=i+4){
f2=0;
}
if(f(b[3])>=i&&f(b[3])<=i+4){
f1=1;
}
if(f(b[4])>=i&&f(b[4])<=i+4){
f1=1;
}
if(f(b[5])>=i&&f(b[5])<=i+4){
f1=1;
}
if(f1&&f2){
fl=1;
break;
}
}
if(fl){
cout<<"check\n";
}else{
cout<<"allin\n";
}
return;
}
if(st==2){
if(f(a[2])==3&&f(a[3])==4&&f(a[4])==5&&f(a[5])==14){
st=1;
int fl=0;
for(int i=st+1;i<=10;i++){
int f1=0,f2=1;
if(f(b[1])>=i&&f(b[1])<=i+4){
f2=0;
}
if(f(b[2])>=i&&f(b[2])<=i+4){
f2=0;
}
if(f(b[3])>=i&&f(b[3])<=i+4){
f1=1;
}
if(f(b[4])>=i&&f(b[4])<=i+4){
f1=1;
}
if(f(b[5])>=i&&f(b[5])<=i+4){
f1=1;
}
if(f1&&f2){
fl=1;
break;
}
}
if(fl){
cout<<"check\n";
}else{
cout<<"allin\n";
}
return;
}
}
cout<<"check\n";
}
B. Rectangle Flip 2
题意:
给定 \(n×m\) 的棋盘,每秒会有一个格子破裂(所有格子都会破裂一次),需依次输出前 \(i\) 个格子破裂后,棋盘上所有格子均完好的矩形数量(共输出 \(n×m\) 行)。
思路:
每破裂一个格子,就枚举仅包含这一个破裂格子的矩形,将其减去。对每个格子维护上方和下发最近的格子,然后对当前破裂的格子往左右枚举,直到枚举到同行的最近的左右两个破裂的格子或边界,按此方法计数,计数完更新维护信息,时间复杂度为 \(O(nm^2)\)。
代码
点击查看代码
int a[505][505],b[505][505];
int A[505][505];
void solve() {
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
b[i][j]=n+1;
}
}
int s=n*(n+1)/2*m*(m+1)/2;
for(int o=1;o<=n*m;o++){
int x,y;
cin>>x>>y;
int LU=0,LD=n+1;
for(int i=y;i>=1;i--){
if(A[x][i])break;
LU=max(a[x][i],LU);
LD=min(b[x][i],LD);
int RU=0,RD=n+1;
for(int j=y;j<=m;j++){
if(A[x][j])break;
RU=max(a[x][j],RU);
RD=min(b[x][j],RD);
int U=max(LU,RU);
int D=min(LD,RD);
// cout<<i<<' '<<j<<' '<<U<<' '<<D<<endl;
s-=(x-U)*(D-x);
}
}
cout<<s<<endl;
for(int i=1;i<=x;i++){
b[i][y]=min(b[i][y],x);
}
for(int i=x;i<=n;i++){
a[i][y]=max(a[i][y],x);
}
A[x][y]=1;
}
}

浙公网安备 33010602011771号