EOJ Monthly 2017.12
A
签到
B. 在哈尔滨的寒风中
题意
给一个n×m的棋盘,问有多少对点可以互相到达(可以经过若干步)(n,m<=1e9)
分析
很显然,当棋盘很大时,所有点对都可以互相到达(比如:象棋棋盘),模拟可得:这个边界为3*4(大于等于3*4所有点都可到达),其他情况手动暴力模拟即可
还有另一种思路:找不到边界是我们可以假设边界为100*100(因为数据很大,不能直接暴力dfs),剩下暴力dfs找属于同一联通块的即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 1e5+5 ; const int maxm = 1e5 + 3; const ll mod = 1e9+7; ll n,m; int main() { scanf("%lld%lld", &n ,&m); if(n>m) swap(n,m); if(n>=3&&m>=4) { ll ans=n*m; printf("%lld\n", (ans*(ans-1))/2); } else if(n==3&&m==3) printf("28\n"); else if(n==2) { ll ans1=((m+1)/2); ll ans2= (m-(m+1)/2); cout<<(ans1*(ans1-1))+(ans2*(ans2-1))<<endl; } else cout<<0<<endl; return 0; }
*C. 易位构词
题意
给一个单词s (1≤|s|≤105),问你是否存在一种改变字符的顺序使得每个字符都不在原来的位置上,存在输出单词,否则输出"impossible"
分析
直接将单词排序,循环向右移动最大连续相同的字符个数即可(具体实现还是有点困难的,学习!!!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; const int maxm=1e5+5; int cnt[maxn]; char str[maxn]; char ans[maxn]; struct node { char s;int id; friend bool operator < (node x, node y) { if(cnt[x.s]!=cnt[y.s]) return cnt[x.s]>cnt[y.s] ; return x.s<y.s; } }a[maxn]; int main() { scanf("%s", str); int n=strlen(str); for(int i=0;i<n;i++) a[i]={str[i],i}, cnt[str[i]]++; sort(a,a+n); int mx=0; char ss=a[0].s; int i; for(i=0;i<n;i++) if(a[i].s!=ss) break; mx=i; if((mx<<1)>n) printf("impossible\n"); else { for(int i=0;i<n;i++) str[(i+mx)%n]=a[i].s; for(int i=0;i<n;i++) ans[a[i].id]=str[i]; ans[n]='\0'; printf("%s", ans); } return 0; }
D. 唐纳德和他的数学老师
题意
简单二分图题
分析
直接建边,跑匈牙利算法,找不到就跳出即可,用到欧拉函数,注意分解不了时,要考虑进去
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn = 3000+10; const int N = 1e6+5; int prime[N], a[maxn]; bool ok[N],used[N]; int boy[N]; int head[N]; int num; int cnt; struct node { int nex, to; }edge[N]; void addedge(int u,int v) { ++num; edge[num].to=v; edge[num].nex=head[u]; head[u]=num; } void init() { cnt=num=0; memset(ok,0, sizeof(ok)); memset(head,0,sizeof(head)); memset(boy, 0, sizeof(boy)); } void ol() { ok[1]=1; for(int i=2;i<1005;i++) { if(!ok[i]) { prime[cnt++]=i; for(int j=i;j<1005;j+=i) { ok[j]=1; } } } } bool found(int x) { for(int i=head[x]; i!=0; i=edge[i].nex) { int u=edge[i].to; if(!used[u]) { used[u]=1; if(boy[u]==0 || found(boy[u])) { boy[u]=x; return 1; } } } return 0; } int main() { int n; ol(); scanf("%d", &n); for(int i=1;i<= n;i++) { scanf("%d", &a[i]); int ans=a[i]; for(int j=0;j<cnt;j++) { if(prime[j]>ans) break; if(ans%prime[j]==0) addedge(i,j+1); while(ans&&ans%prime[j]==0) ans/=prime[j]; } if(ans!=1) addedge(i,ans); } int sum=0; for(int i=1;i<=n;i++) { memset(used,0,sizeof(used)); if(found(i)) sum++; else break; } printf("%d\n", sum); return 0; }
要么优秀要么生锈