2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)
Problem A Exam
题意:两人在做判断题,告诉你一个人有k题时正确的,问第二个人最多有多少题是正确的。
题解:那我们只要判断一下有多少题是一致的,一致的和k值相比较一下,然后选出最大的,然后不一致的和length-k相比较一下,就可以得出了答案。
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof a) using namespace std; char mp[10][10]; string s1; string s2; int main() { int k; cin>>k; cin>>s1>>s2; int ans = 0; for(int i=0;i<s1.size();i++) { if(s1[i]==s2[i]) { ans++; } } int pp = (ans>=k)?k:ans; int qq = (pp==k)?(s1.size()-ans):(s1.size()-k); cout<<pp+qq<<endl; }
Problem B Coprime Integers
题意:给出两个区间,问这两区间内能组成有多少组可以组成gcd等于1的组。
题解:莫比乌斯反演板子题。
//#include<bits/stdc++.h> #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define ll long long #define mod 998244353 #define pdd pair<double,double> #define mem(a,x) memset(a,x,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0) using namespace std; const long long INF = 1e18+5; const int inf = 0x3f3f3f3f; const double eps=1e-6; const int MAXN=550005; const double pi=acos(-1); inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;} inline void read(int &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();} const int N = 1e7; ll mu[N + 5], p[N + 5]; bool flg[N + 5]; void init() { int tot = 0; mu[1] = 1; for (int i = 2; i <= N; ++i) { if (!flg[i]) { p[++tot] = i; mu[i] = -1; } for (int j = 1; j <= tot && i * p[j] <= N; ++j) { flg[i * p[j]] = 1; if (i % p[j] == 0) { mu[i * p[j]] = 0; break; } mu[i * p[j]] = -mu[i]; } } for (int i = 1; i <= N; ++i) mu[i] += mu[i - 1]; } ll solve(int n, int m) { ll res = 0; for (int i = 1, j; i <= std::min(n, m); i = j + 1) { j = std::min(n / (n / i), m / (m / i)); res += (mu[j] - mu[i - 1]) * (n / i) * (m / i); } return res; } int main() { int T, a,b,c,d; init(); scanf("%d%d%d%d",&a,&b,&c,&d); if(a==1&&c==1) { cout<<solve(b,d); } else if(a==1) { cout<<solve(b,d)-solve(b,c-1); } else if(c==1) { cout<<solve(b,d)-solve(a-1,d); } else { ll num=solve(b,d)-solve(a-1,d)-solve(b,c-1)+solve(a-1,c-1); printf("%lld\n",num); } return 0; }
Problem C Contest Setting
题意:给你n道题目,选k题,要问你有多少种不同的选择方法,并且要保证每次选择要不同难度的题。
题解:简单的dp,先统计一下,每种相同难度系数的有多少种,由于数据不大,我们可以用二维dp,前i个数中挑j个数,如果选择这个数我们就加上dp[i-1][j-1]*mp[i],mp[i]为这个难度的个数,如果不选就为dp[i-1][j],所以我们可以求出状态方程就为dp[i][j] = dp[i-1][j-1]*mp[i]+dp[i-1][j];简而言之,就是在前i个数选j个数就为现在这个选上加不选上的个数。
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int maxn = 1010; const int mod = 998244353; ll a[maxn]; map<ll,ll>mp; ll num[maxn]; ll dp[maxn][maxn]; map<ll,ll>::iterator it; int main() { int n,k; cin>>n>>k; int count = 0; dp[0][0] = 1; for(int i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+n+1); for(int i=1;i<=n;i++) { if(!mp[a[i]]) { mp[a[i]] = ++count; } num[mp[a[i]]]++; } for(it = mp.begin();it!=mp.end();it++) { //cout<<it->first<<endl; for(int j=0;j<=k;j++) { //cout<<it->second<<endl; ll tt=dp[it->second-1][j]; if(j!=0) tt+=dp[it->second-1][j-1]*num[it->second]; dp[it->second][j]=(dp[it->second][j]+tt)%mod; //cout<<dp[it->second][j]<<endl; } } cout<<dp[count][k]%mod<<endl; return 0; }
Problem G Goat on a Rope
题意:给出一个矩形和一个矩形外一点求这点到矩形的最小距离。
题解:把矩形外分为三种情况,就是在矩形的x轴范围内,和在矩形y轴范围内,然后其余部分。
#include<bits/stdc++.h> using namespace std; int t[1010]; double find(int x,int y,int x1,int x2,int y1,int y2) { return min(min(sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1)),sqrt((x-x2)*(x-x2)+(y-y1)*(y-y1))),min(sqrt((x-x1)*(x-x1)+(y-y2)*(y-y2)),sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2)))); } int main() { int x,y,x1,y1,x2,y2; cin>>x>>y>>x1>>y1>>x2>>y2; int minx = min(x1,x2); int maxx = max(x1,x2); int miny = min(y1,y2); int maxy = max(y1,y2); if(x>=minx&&x<=maxx) { printf("%.3lf",1.0*(min(abs(y-y1),abs(y-y2)))); } else if(y>=miny&&y<=maxy) { printf("%.3lf",1.0*(min(abs(x-x1),abs(x-x2)))); } else{ printf("%.3lf",find(x,y,x1,x2,y1,y2)); } }
Problem H Repeating Goldbachs
题意:就是给你一个数,可以变成两个质数的之和,然后这个数就变成两个质数的差,并且要保证这两质素差要最大,如果这两数之差小于4,那么就结束递归。
题解:因为我们给出的数据不大,所以我们先给个欧拉筛筛选出所有的质数,直接递归暴力求解就可以了。
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof a) #define ll long long int using namespace std; const int maxn = 1e6 + 10; int prime[maxn]; int visit[maxn]; void Prime(){ mem(visit,0); mem(prime, 0); for (int i = 2;i <= maxn; i++) { // cout<<" i = "<<i<<endl; if (!visit[i]) { prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数 } for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) { // cout<<" j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl; visit[i*prime[j]] = 1; if (i % prime[j] == 0) { break; } } } } int ans = 0; void dfs(int x,int q) { if(x<4) { ans = max(ans,q); return; } for(int i=1;prime[i]<=x-1;i++) { if(visit[x-prime[i]]==0) { dfs(abs(x-2*prime[i]),q+1); break; } } } int main() { int x; Prime(); cin>>x; /* for(int i=1;i<=100;i++) { cout<<prime[i]<<endl; }*/ dfs(x,0); cout<<ans<<endl; }
Problem J Time Limits
题意:给你n个数,和一个k值求,最大数的k倍整数值。
#include<bits/stdc++.h> using namespace std; int t[1010]; int main() { int n,s; cin>>n>>s; for(int i=1;i<=n;i++) { cin>>t[i]; } sort(t+1,t+n+1); cout<<t[n]*s/1000+((t[n]*s)%1000?1:0)<<endl; }
Problem L Liars
题意:给你n个人对于说实话人数的区间,问你们在这几个人中最多有多少人说了实话。
题解:暴力枚举说实话的人数,然后判断一下。
#include<bits/stdc++.h> using namespace std; int a[1010],b[1010]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]>>b[i]; } int pp = 0; for(int i=0;i<=n;i++) { int ans = 0; for(int j=1;j<=n;j++) { if(a[j]<=i&&i<=b[j]) { ans++; } } if(ans == i) { pp = i; } } if(!pp) puts("-1"); else{ cout<<pp<<endl; } }