重现赛链接
第一次打了正式的比赛(虽然是线上)摸了个铜,感觉还行但还是失误很多。
签到题开局和学长一起读错题目(英语水平大雾)十多分钟才出了第一题。
还好后面A的题目全都是1发,保了个铜尾。
代码
暴力打表代码
#include
using namespace std;
typedef long long LL;
const int N=5005,mod=998244353;
LL fac[N*N]={
1,1};//0!是1啊!
LL qmi(LL a, LL k, LL p) // 快速幂模板
{
int res = 1 % p;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
LL C(LL a, LL b, LL p) // 通过定理求组合数C(a, b)
{
if (a < b) return 0;
LL x = 1, y = 1; // x是分子,y是分母
for (int i = a, j = 1; j <= b; i --, j ++ )
{
x = (LL)x * i % p;
y = (LL) y * j % p;
}
return x * (LL)qmi(y, p - 2, p) % p;
}
LL lucas(LL a, LL b, LL p)
{
if (a < p && b < p) return C(a, b, p);
return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
int main(){
freopen ( "db.out" , "w" , stdout ) ;
for(int i=2;i<=N*N;i++)fac[i]=fac[i-1]*i%mod;
for(LL k=1;k<=5000;k++){
LL n=k;
LL ans=0;
for(LL i=1;i<=n;i++)ans=(ans+lucas(n*n-i,n-1,mod)*n%mod*fac[n]%mod*fac[n*n-n]%mod)%mod;
cout<<ans%mod<<",";
}
fclose ( stdout ) ;
}
思路
树形DP没写过,以前只写过一道依赖背包有点类似树形DP。
既然没学过那就学吧!
树形DP入门题:没有上司的舞会
代码
#include
using namespace std;
const int N=1e5+10,mod=998244353;
typedef long long LL;
int n;
vector<int>v[N];
LL f[N][3];
void dfs(int u,int fa){
f[u][0]=f[u][1]=f[u][2]=1;
for(int j:v[u]){
if(j==fa)continue;
dfs(j,u);
//递归完后开始更新子树,然后一层层向上更新
f[u][0]=f[u][0]*(f[j][0]+f[j][1])%mod;
f[u][1]=f[u][1]*(f[j][0]+f[j][1]+f[j][2])%mod;
f[u][2]=f[u][2]*f[j][0]%mod;
}
f[u][1]-=f[u][2];
if(f[u][1]<0)f[u][1]+=mod;
}
int main(){
int T;
while(~scanf("%d",&T)){
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++)v[i].clear();
for(int i=0,a,b;i<n-1;i++){
scanf("%d%d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1,-1);
printf("%lld\n",(f[1][0]+f[1][1])%mod);
}
}
return 0;
}
代码
在这里插入代码片
思路
数论构造 6 p = p + 2 p + 3 p 6p=p+2p+3p 6p=p+2p+3p
代码
#include
using namespace std;
const int N = 1e5;
int t;
int main() {
int T;
long long n;
long long cnt;
cin >> t;
while(t--)
{
cin>>n;
cnt=6*n;
cout<<cnt<<" "<<3<<endl;
cout<<cnt/6<<" "<<cnt/3<<" "<<cnt/2<<endl;
}
}
思路
C语言模拟题,但是开局三人蜜汁凌乱读错题目
代码
#include
using namespace std;
const int N=15;
int a[20]={
7, 27, 41, 49, 63, 78, 108};
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
int sum = 0, each;
for (int i = 0; i < n; i++) {
scanf("%d", &each);
sum += a[each-1];
}
if (sum >= 120) {
printf("%d\n", sum -50);
} else if (sum >= 89) {
printf("%d\n", sum - 30);
} else if (sum >= 69) {
printf("%d\n", sum - 15);
} else {
printf("%d\n", sum);
}
}
return 0;
}
思路
几何题目
罗德里格旋转公式
需要注意的是是绕单位向量,所以要转换一下
代码
#include
using namespace std;
const int N = 5007, M = 50007, INF = 0x3f3f3f3f;
const double DINF = 1e18, eps = 1e-8, Pi=acos(-1.0);
inline double R_to_D(double rad)//弧度转角度
{
return 180/Pi*rad; }
inline double D_to_R(double D)//角度转弧度
{
return Pi/180*D; }
struct Point{
double x, y, z;
Point(double x = 0, double y = 0, double z = 0):x(x), y(y), z(z){
}//构造函数
};
//!注意区分点和向量
typedef Point Vector;
//向量平移之后还是那个向量,所以只需要原点和向量的终点即可
//!向量 + 向量 = 向量,点 + 向量 = 向量
Vector operator + (Vector A, Vector B){
return Vector(A.x + B.x, A.y + B.y, A.z+B.z);}
//!点 - 点 = 向量(向量BC = C - B)
Vector operator - (Point A, Point B){
return Vector(A.x - B.x, A.y - B.y, A.z-B.z);}
//!向量 * 数 = 向量
Vector operator * (Vector A, double p){
return Vector(A.x * p, A.y * p, A.z * p);}
//!向量 / 数 = 向量
Vector operator / (Vector A, double p){
return Vector(A.x / p, A.y / p, A.z / p);}
//!点/向量的比较函数
bool operator < (const Point& a, const Point& b) {
if(a.x!=b.x)return a.x<b.x;
else if(a.y!=b.y)return a.y<b.y;
else return a.z<b.z;
}
//!点积(满足交换律)
double Dot(Vector A, Vector B){
return A.x * B.x + A.y * B.y + A.z * B.z;}
//叉乘
Vector multi(Vector A,Vector B){
return Vector(A.y*B.z-B.y*A.z,B.x*A.z-A.x*B.z,A.x*B.y-B.x*A.y);}
//转单位向量
Vector To_UnitVector(Vector U){
double k=sqrt(Dot(U,U));
return Vector(U/k);
}
//罗德里格斯公式
Vector eval(Vector U,Vector V,double r){
return V*cos(r)+U*Dot(U,V)*(1-cos(r))+multi(U,V)*sin(r);
}
int main(){
int T;
while(~scanf("%d",&T)){
while(T--){
double A,B,C,x,y,z,r;
Vector U,V,P,Q;
scanf("%lf %lf %lf %lf %lf %lf %lf",&A,&B,&C,&x,&y,&z,&r);
U={
A,B,C};V={
x,y,z};
U=To_UnitVector(U);
P=eval(U,V,D_to_R(r));
Q=eval(U,V,D_to_R(-r));
if(P.z>Q.z)printf("%.8lf %.8lf %.8lf\n",P.x,P.y,P.z);
else printf("%.8lf %.8lf %.8lf\n",Q.x,Q.y,Q.z);
}
}
}
思路
第一次看以为是什么图论题目先放了,后面仔细瞅瞅发现和连通性有关,果断并查集维护连通块大小。然后对查询排序后离线查询,然后再用类似最小生成树的方式慢慢增加路径。
每次合并的贡献是:
C [ i ] = i ∗ ( i − 1 ) / 2 C[i]=i*(i-1)/2 C[i]=i∗(i−1)/2
C [ s i z e [ f a ] + s i z e [ f b ] ] − C [ s i z e [ f a ] ] − C [ s i z e [ f b ] ] = s i z e [ f a ] ∗ s i z e [ f b ] C[size[fa]+size[fb]]-C[size[fa]]-C[size[fb]]=size[fa]*size[fb] C[size[fa]+size[fb]]−C[size[fa]]−C[size[fb]]=size[fa]∗size[fb]
嗯!思路清晰的一批,然后我写烂了。find函数忘记递归完存f[x],造成T,比赛结束也没查出来。当场谢罪呜呜呜。
顺便,有人说HDU上数组越界也可能爆TLE
代码
#include
using namespace std;
typedef long long LL;
int T,n,m,Q;
const int N=2e6+10;
struct G{
int u,v,k;
}g[N];
struct query{
int id,p;
}q[N];
LL C[N],ans[N],siz[N],f[N];
bool cmp(G A,G B){
return A.k>B.k;
}
bool cmp2(query A,query B){
return A.p>B.p;
}
void init(){
for(LL i=1;i<=N;i++)C[i]=i*(i-1)/2;//(不开longlong会爆)
}
int find(int x)
{
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
inline LL read(){
LL x=0,y=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')y=-1;c=getchar();}
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x*y;
}
int main(){
init();
while(~scanf("%d",&T)){
while(T--){
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=n;i++){
f[i]=i;
siz[i]=1;
}
for(int i=1;i<=m;i++){
g[i].u=read(),g[i].v=read(),g[i].k=read();
}
sort(g+1,g+1+m,cmp);
for(int i=1;i<=Q;i++){
q[i].p=read();
q[i].id=i;
}
sort(q+1,q+1+Q,cmp2);
int pos=1;
LL sum=0;
for(int i=1;i<=Q;i++){
while(pos<=m&&g[pos].k>=q[i].p){
if(pos>m)break;
int fa=find(g[pos].u);
int fb=find(g[pos].v);
if(fa!=fb){
sum+=C[siz[fa]+siz[fb]]-C[siz[fa]]-C[siz[fb]];//这里这个式子可以简化成siz[fa]*siz[fb]
f[fb]=fa;
siz[fa]+=siz[fb];
}
pos++;
}
ans[q[i].id]=sum;
}
for(int i=1;i<=Q;i++)printf("%lld\n",ans[i]);
}
}
return 0;
}
思路
模拟,读题,打表!
代码
# include
using namespace std;
map<string, string> mp;
bool func(string str) {
mp["iu"] = "q";
mp["ei"] = "w";
mp["uan"] = "r";
mp["ue"] = "t";
mp["un"] = "y";
mp["sh"] = "u";
mp["ch"] = "i";
mp["uo"] = "o";
mp["ie"] = "p";
mp["ong"] = "s";
mp["iong"] = "s";
mp["ai"] = "d";
mp["en"] = "f";
mp["eng"] = "g";
mp["ang"] = "h";
mp["an"] = "j";
mp["uai"] = "k";
mp["ing"] = "k";
mp["uang"] = "l";
mp["iang"] = "l";
mp["ou"] = "z";
mp["ia"] = "x";
mp["ua"] = "x";
mp["ao"] = "c";
mp["zh"] = "v";
mp["ui"] = "v";
mp["in"] = "b";
mp["iao"] = "n";
mp["ian"] = "m";
if (mp[str] != "") {
return true;
}
if (mp[str] == "") {
return false;
}
}
string judge(string str) {
if (str.length() == 1) {
cout << str << str ;
} else if (str == "ang") {
cout << "ah";
} else if (str == "an") {
cout << "an";
} else if (str == "ai") {
cout << "ai";
} else if (str == "en") {
cout << "en";
} else if (str == "ao") {
cout << "ao";
}
else {
string substr = str.substr(0, 2);
if (func(substr)) {
if (func(str.substr(2))) {
cout << mp[substr] << mp[str.substr(2)] ;
}
else
cout << mp[substr] << str.substr(2) ;
}
else
{
if (func(str.substr(1))) {
cout << str[0] << mp[str.substr(1)] ;
}
else
cout << str[0] << str.substr(1) ;
}
}
return "";
}
int main() {
string str;
char s[6000];
while (gets(s)) {
for (int i = 0; s[i];i++){
if (s[i] != ' ') {
str += s[i];
} else {
judge(str);
cout << " ";
str = "";
}
}
judge(str);
str="";
s[0]=0;
cout << endl;
}
return 0;
}