eg:A題大模擬(感覺),D題dp,F題沒看。這三題沒有出,其餘七道題的題解,這次還是按照難度順序來吧。
比賽傳送門
G. Sheba’s Amoebas
題意:判斷連通圓環的個數。
題解:bfs dfs亂搞即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,m,ans,stx,sty;
int vis[110][110],tmp[110][110];
int dis[10][2]={1,0,-1,0,0,1,0,-1,1,1,1,-1,-1,1,-1,-1};
char s[110][110];
void dfs(int x,int y,int tot){
int flag=0;
for(int i=0;i<8;i++){
int nx=x+dis[i][0],ny=y+dis[i][1];
if(nx<0 || nx>=n || ny<0 || ny>=m || s[nx][ny]!='#' || vis[nx][ny] || tmp[nx][ny])continue;
vis[nx][ny]=1;
tmp[nx][ny]=1;
dfs(nx,ny,tot+1);
vis[nx][ny]=0;
flag=1;
}
if(!flag && tot>1){
for(int i=0;i<8;i++){
int nx=x+dis[i][0],ny=y+dis[i][1];
if(nx==stx && ny==sty){
ans++;
return;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%s",&s[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
memset(vis,0,sizeof(vis));
if(!vis[i][j] && s[i][j]=='#'){
vis[i][j]=1;
tmp[i][j]=1;
stx=i,sty=j;
dfs(i,j,1);
}
}
printf("%d\n",ans);
return 0;
}
H. Zebras and Ocelots
題意:一排動物Z和O,每次將最底下的O變成Z,同是該O底下的Z全變成O,問一直到全爲Z需要操作幾次。
題解:模擬一下會發現,就是二進制加法,Z爲1O爲0,那(1<<(n+1)-1-給出的數字即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
char a[100],ch;
int n;
ll sum,ans,f[100];
int main(){
f[0]=1;
for(int i=1;i<=60;i++)f[i]=f[i-1]*2;
scanf("%d%c",&n,&ch);
for(int i=n-1;i>=0;i--)scanf("%c%c",&a[i],&ch);
for(int i=0;i<n;i++)ans=ans+f[i];
for(int i=0;i<n;i++)
if(a[i]=='Z')sum=sum+f[i];
printf("%lld\n",ans-sum);
return 0;
}
I. Racing Around the Alphabet
題意:一個半徑給定的圓盤上面有不同的字abcdefghijklmnopqrtsuvwxyz空格和單引號,先給出一句話,問怎麼使人在圓盤上移動能寫出整句話來。
題解:正着跑反正跑比較一下,取個小累加即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int T;
char s[maxn],ch;
map<char,int>a;
int main(){
for(char i='A';i<='Z';i++)a[i]=i-'A'+1;
a[' '] = 27;a['\'']=28;
double dis = 3.1415926535 * 60 / 28;
scanf("%d%c",&T,&ch);
while(T--){
cin.getline(s,200);
int len=strlen(s),pos=s[0],cnt=0;
for(int i=1;i<len;i++){
int cmp=abs(a[s[i]]-a[s[i-1]]);
cnt+=min(cmp,28-cmp);
}
double ans=(double)cnt*dis/(double)15.0+(double )len;
printf("%.10lf\n",ans);
}
return 0;
}
C. Urban Design
題意:一個平面被若干條直線劃分,每個區域都需要被劃分爲商業區或者居民區,先給出兩個點,問是否在同一個區。
題解:判斷兩點經過多少條直線,如果經過偶數條直線說明可以劃分爲同一個區,反之不可以。用叉乘判斷是否相交。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eps=1e-6;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
struct arr{
double s1,s2,e1,e2;
}a[maxn];
int n,q;
double cross(arr a,double x,double y){
return (a.s1-x)*(a.e2-y)-(a.e1-x)*(a.s2-y);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lf%lf%lf%lf",&a[i].s1,&a[i].s2,&a[i].e1,&a[i].e2);
scanf("%d",&q);
while(q--){
double s1,s2,e1,e2;
int sum=0;
scanf("%lf%lf%lf%lf",&s1,&s2,&e1,&e2);
for(int i=1;i<=n;i++)
if(cross(a[i],s1,s2)*cross(a[i],e1,e2)>eps)continue;
else sum++;
if(sum%2)puts("different");
else puts("same");
}
return 0;
}
J. Lost Map
題意:給出最短路的圖,反推原圖。
題解:最小生成樹,依次加邊即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N=3e3+10;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}int n,cnt;
int a[N][N]; int f[N];
struct node{
int u,v,w;
} E[N*N],ans[N];
int getf(int x){
return x==f[x] ? x : f[x] = getf(f[x]);
}
bool cmp(node a,node b){
return a.w < b.w;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) f[i] = i;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
if(j<i) {
++cnt;
E[cnt].u = i, E[cnt].v = j, E[cnt].w = a[i][j];
}
}
}
sort(E+1,E+cnt+1,cmp);
int mk = 0;
for(int i=1;i<=cnt;i++){
node t = E[i];
int u = t.u, v = t.v; swap(u,v);
if(getf(u)!=getf(v)){
f[getf(u)] = getf(v); //cout<<u<<' '<<v<<' '<<getf(u)<<' '<<getf(v)<<" h"<<endl;
++mk;
ans[mk].u = u, ans[mk].v = v;
}
}
for(int i=1;i<=mk;i++){
printf("%d %d\n",ans[i].u,ans[i].v);
}
return 0;
}
E. Is-A? Has-A? Who Knowz-A?
題意:定義兩種關係 is 和 has,A is B代表A可以是B 但是 B不可以是 A,A has B代表 B是A的兒子。
給出若干條關係定義 再給出若干條詢問 判斷正誤。
題解:可以bfs亂搞 也可以傳遞閉包。注意到is是可以無限傳遞下去的,而has的關係與is的關係有關。所以先處理完is關係矩陣,再處理has關係矩陣。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
string a,b,c;
map<string,int>mmap;
int n,m,T;
int is[510][510],has[510][510];
int main(){
// freopen("1.txt","w",stdout);
scanf("%d%d",&m,&T);
for(int i=1;i<=m;i++){
cin>>a>>b>>c;
if(!mmap.count(a))mmap[a]=++n;
if(!mmap.count(c))mmap[c]=++n;
if(b[0]=='i')is[mmap[a]][mmap[c]]=1;
else has[mmap[a]][mmap[c]]=1;
}
for(int i=1;i<=n;i++)is[i][i]=1;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
is[i][j]=is[i][j]||(is[i][k] && is[k][j]);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
has[i][j]=has[i][j]||(has[i][k] && has[k][j]);
has[i][j]=has[i][j]||(is[i][k] && has[k][j]);
has[i][j]=has[i][j]||(has[i][k] && is[k][j]);
}
for(int ttt=1;ttt<=T;ttt++){
cin>>a>>b>>c;
printf("Query %d: ",ttt);
if(!mmap.count(a))mmap[a]=++n;
if(!mmap.count(c))mmap[c]=++n;
if(b[0]=='i'){
if(is[mmap[a]][mmap[c]])puts("true");
else puts("false");
}else{
if(has[mmap[a]][mmap[c]])puts("true");
else puts("false");
}
}
return 0;
}
B. Pokemon Go Go
題意:二維平面tsp問題,每種寶可夢只需抓一隻,問最少花費。
題解:狀壓dp,用1表示該點是否需要走到,0就是不走。然後類似於floyd的轉移即可。最後用dfs判斷每種只取一個的花費,選擇一個最小的。表示 i 這種二進制情況到 j 這個點的最小花費。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int n,m,ans;
struct arr{
int x,y;
}a[22];
int d[22][22],f[1<<22][22];
map<string,int>mmap;
string s;
vector<int>v[22];
void dfs(int cnt,int x){
if(cnt==m){
ans=min(ans,f[x][0]);
return;
}
for(int i=0;i<v[cnt+1].size();i++)
dfs(cnt+1,(x|(1<<v[cnt+1][i])));
return;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
cin>>s;
if(mmap.count(s))v[mmap[s]].push_back(i);
else {
mmap[s]=++m;
v[mmap[s]].push_back(i);
}
}
a[0].x=0,a[0].y=0;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
d[i][j]=abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y);
memset(f,INF,sizeof(f));
f[0][0]=0;
for(int i=0;i<(1<<(n+1));i++)
for(int j=0;j<=n;j++)
for(int k=0;k<=n;k++)
if((i & (1<<j))==0)
f[i|(1<<j)][j]=min(f[i|(1<<j)][j],f[i][k]+d[k][j]);
ans=INF;
dfs(0,1);
printf("%d\n",ans);
return 0;
}