9.18 正睿 CSP 七连测 day4
T1
诈骗题,这个题看着挺吓人,实际上没有这么吓人。我们只需要对这个矩阵进行分割即可,分割成不相等的 \(3\times 3\) 的小格子,加起来即可。代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 201
#define M 201
using namespace std;
const int INF=0x3f3f3f3f;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int a[N][N],n,m,ans;
const int Begin[]={2,1,2};
inline int Get(){
char c=getchar();for(;!isdigit(c);c=getchar());
return c-'0';
}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=Get();
}
}
for(int i=Begin[n%3];i<=n;i+=3){
for(int j=Begin[m%3];j<=m;j+=3){
ans+=a[i][j];
}
}
printf("%d\n",ans);
return 0;
}
T2
这个题还是比较巧妙地,巧妙的地方在于用并查集,然后把整个问题转换为连通块合并,所以最终的答案就是连通块的个数。这个建模比较巧妙,其切入点在于整个题目与行和列的相关性。
代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 1010
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
struct DSU{
int fa[N<<1],size[N<<1];
inline void Init(int n){for(int i=1;i<=n;i++) fa[i]=i,size[i]=1;}
inline int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);}
inline bool Merge(int a,int b){
int faa=Find(a),fab=Find(b);if(faa==fab) return 0;if(size[faa]<size[fab]) swap(faa,fab);
fa[fab]=faa;size[faa]+=size[fab];return 1;
}
inline int GetAns(int n){
int res=0;
for(int i=1;i<=n;i++) if(fa[i]==i) res++;
return res;
}
}dsu;
int n,m,a[N][N],ans,num;
inline int GetInt(){
char c=getchar();for(;!isdigit(c);c=getchar());
return c-'0';
}
int main(){
read(n);read(m);dsu.Init(n+m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
a[i][j]=GetInt();
if(a[i][j]) dsu.Merge(i,j+n);else num++;
}
int now=dsu.GetAns(n+m);
ans=(now-1)*4+(num-now+1)*3;
// printf("now:%d\n",now);
printf("%d\n",ans);
return 0;
}
T3
我们考虑先想这个题目的简单情况,如果给定的这条直线是一条竖直的直线怎么做,不难发现,如果我们把所有点映射到 \(x\) 轴上,那么答案一定存在于相邻两个点之间的斜率。
所以我们考虑把所有点映射到 \(-\frac{Q}P\) 上,这个东西等价于我们算出这个点在这个斜率下的在 \(y\) 轴上的截距。枚举即可。代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define int long long
#define uint unsigned int
#define ull unsigned long long
#define N 1000100
#define M number
using namespace std;
const int INF=1e9+7;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int n,P,Q,fenzi=1,fenmu;
dd K,cha=INF;
struct Point{
int x,y;
inline Point(){}
inline Point(int x,int y) : x(x),y(y) {}
inline bool operator < (const Point &b) const{
return -x*P+y*Q<-b.x*P+b.y*Q;
}
}p[N];
inline dd CalcK(Point a,Point b){
if(a.x==b.x) return INF;
return (dd)(b.y-a.y)/(dd)(b.x-a.x);
}
inline int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
signed main(){
read(n);read(P);read(Q);
for(int i=1;i<=n;i++){read(p[i].x);read(p[i].y);}
sort(p+1,p+n+1);K=(dd)P/(dd)Q;
for(int i=1;i<=n-1;i++){
dd nowk=CalcK(p[i],p[i+1]);
dd nowcha=fabs(nowk-K);
if(nowcha<cha){
cha=nowcha;fenzi=abs(p[i+1].y-p[i].y);fenmu=abs(p[i+1].x-p[i].x);
}
}
int g=gcd(fenzi,fenmu);
printf("%d/%d\n",fenzi/g,fenmu/g);
return 0;
}
T4
不难想到 dp,我们设 \(f_{i,j}\) 表示考虑把 \(j\) 个任务分给前 \(i\) 个人其中满足至少一个人高兴的方案数。那么首先,我们可以让 \(f_{i,j}=\dbinom{j}{i}(j-i)^{i-1}\),表示我让第 \(i\) 个人开心,其余人随意,否则我们枚举第 \(i\) 个人拿多少任务,从前面转移过来。注意第一个赋值是有条件的。代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 360
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
int f[N][N],n,c[N][N];
inline int ksm(int a,int b,int mod){
int res=1;while(b){if(b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}return res;
}
inline void PreWork(){
for(int i=0;i<=n;i++)
for(int j=0;j<=i;j++){
if(j==0||j==i) c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
int main(){
read(n);PreWork();
for(int i=1;i<=n;i++){
for(int j=0;j<=n;j++){
if(j>=i){f[i][j]=1ll*ksm(i-1,j-i,mod)*c[j][i]%mod;}
// printf("i:%d j:%d f:%d\n",i,j,f[i][j]);
for(int k=0;k<=j;k++){
// printf("k:%d\n",k);
if(k==i) continue;
f[i][j]=(f[i][j]+1ll*f[i-1][j-k]*c[j][k]%mod)%mod;
// printf("i:%d j:%d f:%d\n",i,j,f[i][j]);
// printf("i:%d j:%d c:%d\n",i,j,c[i][j]);
}
// printf("i:%d j:%d f:%d\n",i,j,f[i][j]);
}
}
printf("%d\n",f[n][n]);
return 0;
}