National Contest for Private Universities (NCPU), 2019
-
A. Minimum Factorial as a Multiple
- 通过率:80.68%
- 正确提交 / 总提交:284 / 352
-
B. Population Count
- 通过率:93.73%
- 正确提交 / 总提交:269 / 287
-
C. Boxes
- 通过率:22.4%
- 正确提交 / 总提交:71 / 317
-
D. RSSI fingerprinting
- 通过率:56.38%
- 正确提交 / 总提交:212 / 376
-
E. Generalized Pascal's Triangle
- 通过率:48.5%
- 正确提交 / 总提交:146 / 301
-
F. Sequence Decoding
- 通过率:77.98%
- 正确提交 / 总提交:170 / 218
-
G. Cycles
- 通过率:19.8%
- 正确提交 / 总提交:40 / 202
-
H. Countable Rational Numbers
- 通过率:48.28%
- 正确提交 / 总提交:14 / 29
A-Minimum Factorial as a Multiple
题意:求满足 k! mod n = 0 的最小 k枚举 k 即可
#include <stdio.h>
using namespace std;
int fac[20];
int main(){
int m,n;
scanf("%d",&m);
fac[1]=1;
for(int i=2;i<=12;i++)fac[i]=i*fac[i-1];
while(m--){
scanf("%d",&n);
for(int i=1;i<=12;i++){
if(fac[i]%n==0){
printf("%d\n",i);
break;
}
}
}
return 0;
}
B-Population Count
题意:求 b 到 e 区间内的每个数在二进制下 1 的个数之和由于 b 和 e 的范围较小,枚举 b 到 e 区间的每一个数,转化为二进制按位统计即可。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
typedef long long LL;
const LL MOD=1e9+7;
int n;
int solve(int n)
{
int i=0;
while(n)
{
if(n%2==1)
i++;
n/=2;
}
return i;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int b,e;
scanf("%d%d",&b,&e);
LL ans=0;
for(int i=b;i<=e;i++)
{
ans+=solve(i);
///cout<<ans<<endl;
}
cout<<ans<<endl;
}
return 0;
}
C-Boxes
题意:对 1-n 的数列进行元素移动、互换、倒转等操作,求最后序列的奇数位之和.题目解析 利用双向链表记录数列,模拟对应操作。对于数列倒转操作,只需记录倒转次数,奇数次倒 转时将操作 1、2 互换即可。需注意 x,y 相邻时特殊处理。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
struct Node
{
int l,r;
} a[N];
void link(int x,int y)
{
a[x].r=y;
a[y].l=x;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=-1)
{
a[0].r=1;
a[0].l=n;
for(int i=1; i<=n; i++)
{
a[i].l=i-1;
a[i].r=(i+1)%(n+1);
}
int cnt=0;
for(int i=1; i<=m; i++)
{
int op,x,y;
scanf("%d",&op);
if(op==4)
{
cnt++;
}
else
{
if(cnt&1)
{
if(op==1)
op=2;
else if(op==2)
op=1;
}
if(op==1)
{
scanf("%d%d",&x,&y);
if(a[y].l==x)
continue;
int lx=a[x].l,rx=a[x].r,ly=a[y].l,ry=a[y].r;
link(lx,rx);
link(ly,x);
link(x,y);
}
else if(op==2)
{
scanf("%d%d",&x,&y);
if(a[y].r==x)
continue;
int lx=a[x].l,rx=a[x].r,ly=a[y].l,ry=a[y].r;
link(lx,rx);
link(y,x);
link(x,ry);
}
else if(op==3)
{
scanf("%d%d",&x,&y);
if(a[y].r==x)
swap(x,y);
int lx=a[x].l,rx=a[x].r,ly=a[y].l,ry=a[y].r;
if(rx==y)
{
link(lx,y);
link(x,ry);
link(y,x);
}
else
{
link(lx,y);
link(y,rx);
link(ly,x);
link(x,ry);
}
}
}
}
int num = 0;
LL ans = 0;
for(int i = 1; i <= n; i++)
{
num = a[num].r;
//cout<<num<<" ";
if(n%2==0&&cnt%2==1)
{
if(i%2==0)
ans+=num;
}
else
{
if(i%2==1)
ans+=num;
}
}
cout<<ans<<endl;
}
return 0;
}
D-RSSI fingerprinting
题意:求 RSSI 中时间小于 1000,信号强度最大的 3 个(信号强度相等则字典序小优先)将检测时间大于 1000 的删除,其余的按信号强度,字典序排序后输出前三项(不足三项 则全部输出)。
#include <algorithm> //STL通用算法
#include <bitset> //STL位集容器
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque> //STL双端队列容器
#include <exception> //异常处理类
#include <fstream>
#include <functional> //STL定义运算函数(代替运算符)
#include <limits>
#include <list> //STL线性列表容器
#include <map> //STL 映射容器
#include <iomanip>
#include <ios> //基本输入/输出支持
#include<iosfwd> //输入/输出系统使用的前置声明
#include <iostream>
#include <istream> //基本输入流
#include <ostream> //基本输出流
#include <queue> //STL队列容器
#include <set> //STL 集合容器
#include <sstream> //基于字符串的流
#include <stack> //STL堆栈容器
#include <string> //字符串类
#include <vector> //STL动态数组容器
#define ll unsigned long long
using namespace std;
#define rep(i,a,b) for(register ll i=(a);i<=(b);i++)
#define dep(i,a,b) for(register ll i=(a);i>=(b);i--)
//priority_queue<ll,vector<ll>,less<ll> >q;
const ll maxn = 228+66;
const ll maxm=900000+66;
const ll mod=1e9+7;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
const ll INF=99999999;
ll tot=0;
ll n;
bool vis[maxn];
ll f[]= {0,1,2,31,62,1847,3694,57257,114514};
struct node
{
char ch[maxn*100];
int r;
ll t;
} a[maxn];
bool cmp(node a,node b)
{
if(a.r!=b.r) return a.r>b.r;
else return a.ch<b.ch;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
rep(i,1,n)
{
scanf("%s %d %lld",a[i].ch,&a[i].r,&a[i].t);
}
sort(a+1,a+n+1,cmp);
int yy=0;
rep(i,1,n)
{
if(a[i].t<1000&&yy<3)
{
yy++;
printf("%s %d\n",a[i].ch,a[i].r);
}
}
}
return 0;
}
E-Generalized Pascal's Triangle
题意:给出一个立体的杨辉三角,每一层的每个数字等于该数字肩上的三个数字之和。每一个点都可以对下一层的三个点产生贡献,第 i 层第 j 行第 k 列点产生贡献的三个点是第 i+1 行的第 j 列的第 k、k+1 个点及第 j+1 列的第 k+1 个点,递推即可。
本题也可以发现是这样的。
n=3时;(x+y+z)^3
1
3 3
3 6 3
1 3 3 1
1x^3
3x^2y 3x^2z
3xy^2 6xyz 3xyz^2
1y^3 3y^2z 3yz^2 1z^2
知道了(x+y+z)^n=f(n!/(r!*s!*t!)x^r*y^s*z^t),f()表示rst的全排列且r+s+t=n
然后模拟就行了,n!超longlong,大树走起
from queue import PriorityQueue
import sys
sys.setrecursionlimit(10**9)
IA = lambda: [int(x) for x in input().split()]
IM = lambda N: [IA() for _ in range(N)]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
ans=0
MOD = 1000000007
f=[int(1) for i in range(0,25)]
for i in range(1,22):
for j in range(1,i+1):
f[i]*=j;
# print(f[i])
while True:
try:
n = int(input())
num=int(0)
for i in range(0, n + 1):
t1 = n - i
num = int(0)
for j in range(0, n - t1 + 1):
t2 = n - t1 - j
for k in range(0, n - t2 - t1 + 1):
t3 = n - t2 - t1 - k
if (t1 + t2 + t3 != n): continue
num += 1
# print(str(t1)+str(t2)+str(t3),end='%');
if i==num-1:
print(int(f[n] / (f[t1] * f[t2] * f[t3])))
else:
print(int(f[n] / (f[t1] * f[t2] * f[t3])),end=' ')
#except EOFError:break
except:break
F-Sequence Decoding
题意:一个字符串,包含数字、"[" 、"]"、字母 P 和 H ,每一个互相匹配的括号内的字符串 都重复"["前的数字 k 次,把字符串展开为只含字母的字符串。模拟即可,每一个字符入栈,遇到"]"则将栈中"["后的字母全部取出,按照"["前的数字 k 入栈 k 次即可,最后栈中字符串即为答案。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
typedef long long LL;
const LL MOD=1e9+7;
int num[MAXN];
string str[MAXN];
void out(int cnt)
{
cout<<cnt<<endl;
for(int i=0; i<=cnt; i++)
{
cout<<num[i]<<"&"<<str[i]<<endl;
}
cout<<endl;
}
int main()
{
int n;
scanf("%d",&n);
for(int t=1; t<=n; t++)
{
memset(num,0,sizeof(num)) ;
int cnt=0;
string s;
cin>>s;
s="1["+s+']';
int len=s.size();
for(int j=0; j<len; j++)
{
str[j]="";
}
for(int i=0; i<len;)
{
if(s[i]<='9'&&s[i]>='0')
{
num[cnt]=s[i]-'0';
i++;
}
else if(s[i]=='[')
{
cnt++;
i++;
}
else if(s[i]==']')
{
for(int j=0; j<num[cnt-1]; j++)
str[cnt-1]+=str[cnt];
str[cnt]="";
cnt--;
i++;
}
else
{
string temp="";
int j=i;
while(s[j]=='H'||s[j]=='P')
{
temp+=s[j];
j++;
}
str[cnt]+=temp;
i=j;
}
//out(cnt);
}
cout<<str[0]<<endl;
}
return 0;
}
G-Cycles
题意:判断给定无向图是否联通并求出图中环的个数同 Codeforces 11D。本题数据范围较小,使用并查集判断图是否联通,dfs 计算图中环的个数直至三个。最后按照题目要求输出答案即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 20;
int maze[maxn][maxn];
// dp[s][i] : 表示s状态下以 s 状态的最小顶点和顶点i构成的简单环 (这样仍然会重复计算2次)
ll dp[1<<maxn][maxn];
int n,m;
int vis[maxn];
int cnt;
void dfs(int x)
{
if(cnt==n) return ;
for(int i=0;i<n;i++)
{
if(x==i) continue;
if(maze[x][i]==1&&vis[i]==0)
{
//cout<<i<<"^^"<<endl;
vis[i]=1;
cnt++;
if(cnt==n)
return ;
dfs(i);
}
if(cnt==n) return ;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
memset(maze,0,sizeof(maze));
for(int i=0,u,v;i<m;i++) {
scanf("%d%d",&u,&v);
u--,v--;
maze[u][v] = maze[v][u] = 1;
}
ll ans = 0;
for(int i=0;i<n;i++) dp[1<<i][i] = 1;
for(int s=1;s<(1<<n);s++) {
int pre = log2(s & -s);
for(int i=pre;i<n;i++) if(dp[s][i]){ /// 枚举结尾的顶点
for(int j = pre;j<n;j++) if(maze[i][j]){ /// 枚举接下来要连接的顶点
if(s & (1<<j)) { /// 节点j在当前状态中
if (((1<<i)|(1<<j))==s) continue; /// 排除两个节点成环的情况
if(j == pre) ans += dp[s][i];
}
else { /// 节点j不在当前状态中
dp[s|(1<<j)][j] += dp[s][i];
}
}
}
}
//printf("%lld\n",ans/2);
cnt=1;
vis[0]=1;
dfs(0);
//cout<<cnt<<endl;
if(!(cnt==n&&ans/2>=2))
printf("n\n");
else if(ans/2>=3)
printf("y: there are at least three cycles\n");
else
printf("y\n");
}
return 0;
}