来浙理的第一次月赛,嗯我是被大佬吊着打的垃圾。
A:优美数
Description
如果一个数中只有少于三个数字是非零的,那么我们称这个数为优美数,我们定义这个优美数的优美程度为这个数所有数字相加的和。 例如优美数有4,200000,10203,其中4的优美度是4,200000的优美度是2,10203的优美度是6. 数字4231,102306,7277420000,就不是啰。
现在问在【L,R】中,有多少个优美度为x的优美数。
Input
T组数据,T<=5e4. 第一行为组数T。 接下来T行,每组输入L,R,x。1<=L <= R <= 3e18;
Output
每行输出一个对应的答案
Examples
Input
4
1 1000 1
1024 1024 7
65536 65536 15
1 1000000000 20
Output
4
1
0
3024
正确解法:
先dfs,预处理所有的情况,然后对每次询问进行二分求解。
也可用数位DP。
1 #include <algorithm> 2 #include <iterator> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <iomanip> 7 #include <bitset> 8 #include <cctype> 9 #include <cstdio> 10 #include <string> 11 #include <vector> 12 #include <stack> 13 #include <cmath> 14 #include <queue> 15 #include <list> 16 #include <map> 17 #include <set> 18 #include <cassert> 19 using namespace std; 20 21 22 typedef long long ll; 23 24 const int maxn = 3e6+9; 25 int tot = 0; 26 vector<ll>mp[30]; 27 int cnt(ll x){ 28 int res = 0; 29 while(x>0){ 30 res += x%10; 31 x/=10; 32 } 33 return res; 34 } 35 set<int>sss; 36 void dfs(ll x,int cur,int num){ 37 if(cur>19||num > 3)return; 38 39 if(num<=3){ 40 int tmp = cnt(x); 41 mp[tmp].pb(x); 42 // tot++; 43 sss.insert(tmp); 44 // if(cnt(x) == 50)cout<<x<<endl; 45 } 46 for(int i=0;i<=9; i++){ 47 if(i==0)dfs(x*10ll, cur+1,num); 48 else dfs(x*10ll + i, cur+1,num+1); 49 } 50 } 51 int find1(ll x,int id){ 52 int le = 0,ri = mp[id].size() - 1; 53 int res = ri+1; 54 while(le <= ri){ 55 int mid = (le + ri)>>1; 56 57 if(mp[id][mid] < x){ 58 le = mid+1; 59 } 60 else{ 61 res = mid; ri = mid - 1; 62 } 63 } 64 65 return res; 66 } 67 int find2(ll x,int id){ 68 int le = 0,ri = mp[id].size() - 1; 69 int res = 0; 70 while(le <= ri){ 71 int mid = (le + ri)>>1; 72 if(mp[id][mid] > x){ 73 ri = mid - 1; 74 } 75 else { 76 res = mid; 77 le = mid + 1; 78 } 79 } 80 return res; 81 } 82 int main(){ 83 84 // freopen("data.in","r", stdin); 85 // freopen("output.out","w",stdout); 86 for(int i=1; i<=9; i++)dfs(i,1,1); 87 //tot = 720423 88 89 for(int k : sss){//27次 90 sort(mp[k].begin(),mp[k].end()); 91 } 92 93 int t;scanf("%d", &t); 94 while(t--){ 95 ll l,r;int x; 96 scanf("%lld%lld%d", &l, &r, &x); 97 if(x >= 28){ 98 puts("0"); 99 } 100 else if(l<r){ 101 int t1 = find1(l,x); 102 int t2 = find2(r,x); 103 printf("%d ",t2 - t1 + 1); 104 } 105 else if(l==r){ 106 int t1 = lower_bound(mp[x].begin(),mp[x].end(),l) - mp[x].begin(); 107 if(t1<mp[x].size() && mp[x][t1] == l)puts("1"); 108 else puts("0"); 109 } 110 } 111 return 0; 112 }
1 #include <algorithm> 2 #include <iterator> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <iomanip> 7 #include <bitset> 8 #include <cctype> 9 #include <cstdio> 10 #include <string> 11 #include <vector> 12 #include <stack> 13 #include <cmath> 14 #include <queue> 15 #include <list> 16 #include <map> 17 #include <set> 18 #include <cassert> 19 using namespace std; 20 #define se second 21 #define fi first 22 #define ll long long 23 #define Pii pair<int,int> 24 #define Pli pair<ll,int> 25 #define ull unsigned long long 26 #define pb push_back 27 const int N=1e4+10; 28 const int INF=0x3f3f3f3f; 29 const int mod=1e9+7; 30 using namespace std; 31 int a[30]; 32 ll dp[20][30][4][30]; 33 int k; 34 ll dfs(int pos,int now,int num,bool limit){ 35 if(num > 3) return 0; 36 if(pos==-1) return now == k; 37 if(!limit && dp[pos][now][num][k]!=-1) return dp[pos][now][num][k]; 38 int up=limit?a[pos]:9; 39 ll ans=0; 40 for(int i=0;i<=up&&now+i<=k;++i){ 41 ans+=dfs(pos-1,now+i,num+(i!=0),limit&&i==a[pos]); 42 } 43 if(!limit) dp[pos][now][num][k]=ans; 44 return ans; 45 } 46 ll solve(ll x){ 47 int pos=0; 48 if(x==0)return 0; 49 while(x){ 50 a[pos++]=x%10; 51 x/=10; 52 } 53 return dfs(pos-1,0,0,1); 54 } 55 int main(){ 56 // freopen("data1.in", "r", stdin); 57 // freopen("ac.out", "w", stdout); 58 memset(dp,-1,sizeof(dp)); 59 60 int T;scanf("%d",&T); 61 while(T--){ 62 ll l,r; 63 scanf("%I64d%I64d%d",&l,&r,&k); 64 if(k>27)printf("0 "); 65 else printf("%I64d ",solve(r)-solve(l-1)); 66 } 67 68 return 0; 69 }
B:私人奶茶店
Description
小C有一家奶茶店,其中有n种奶茶,每种奶茶都有a【i】个,小C每天都会等概率地从剩余的奶茶中选一杯奶茶喝掉,问小C第K天喝到第m种奶茶的概率是多少。
Input
第一行n,代表奶茶的种类数
第二行n个数,表示a【i】
第三行k,m,表示第k天喝到第m种奶茶的概率
(n<=1e5, 0 < a[i] <= 1e6)
(1<=k<=sum(a[i]), 1<=m<=n)
Output
用最简分数表示。
Examples
Input
2
1 1
1 1
Output
1/2
正确解法:
a[m] / sum 与k无关,最后要gcd
1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 typedef long long ll; 5 const int maxn = 1e5+9; 6 ll a[maxn]; 7 ll gcd(ll a, ll b){ 8 if(b==0)return a; 9 return gcd(b, a%b); 10 } 11 int main(){ 12 // freopen("data5.in", "r", stdin); 13 int n;scanf("%d", &n); 14 ll sum = 0; 15 for(int i=1; i<=n; i++)scanf("%lld", &a[i]),sum+=a[i]; 16 cout<<"sum"<<sum<<endl; 17 int k,m; 18 scanf("%d%d", &k, &m); 19 ll g = gcd(sum,a[m]); 20 printf("%lld/%lld ", 1ll*a[m]/g, 1ll*sum/g); 21 return 0; 22 }
C:素数空间
Description
一天,小明正在搬砖,他收集了n(n<=1e7)种砖,砖的编号1-n这个时候,他突然说了一句,召唤神龙,然后,他穿越到了一个时空,发现这里的东西都是由素数组成的,这里的砖也和素数有关,他的砖也和他一块过来了,只是发生了一些变化,编号为1的砖不见了,编号为素数的砖没有发生变化,编号为合数的砖变成了编号为几块素数的砖(砖的编号和为之前的那个合数),由于这个世界能量太少,所以这些合数的砖尽可能的变成数目少的其他砖。于是小明想请教你他还有多少砖。例如 编号为12的砖会变成编号5 7 的砖 不会变成编号2 3 2 2 3 的砖 编号9的砖会变成编号2 7 的砖 不会变成编号 3 3 3 的砖Input
给你一个T(1<=T<=3e3)Output
一共T行,每一行输出一个结果;Examples
Input
2
3
5
Output
2
5
正确解法:
根据哥德巴赫猜想:
大于二的偶数可以分解为两个素数之和
大于七的奇数可以分解为三个素数之和
(一定可以分解成三个素数之和,也有可能分解为两个,分解成两个其中必然有一个是2,其他就是至少三个)
1.先线性筛出所有的素数。
2.遍历1-le7里的素数、偶合数、奇合数
3.预处理一遍就行了
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e7+5; 4 bool prime[maxn]; 5 int p[maxn]; 6 int tot; 7 void findprime() 8 { 9 for(int i = 2; i < maxn; i ++) prime[i] = true; 10 for(int i = 2; i < maxn; i ++) 11 { 12 if(prime[i]) p[++tot]=i; 13 for(int j=1;j<=tot && i*p[j]<maxn; j++) 14 { 15 prime[i*p[j]]=false; 16 if(i%p[j]== 0) break; 17 } 18 } 19 } 20 int ans[maxn]; 21 int main() 22 { 23 // freopen("g4.in","r",stdin); 24 // freopen("g4.out","w",stdout); 25 findprime(); 26 for(int i=2;i<=maxn;i++) 27 { 28 if(prime[i]==1) ans[i]=ans[i-1]+1; 29 else 30 { 31 if(i%2==0) ans[i]=ans[i-1]+2; 32 else 33 { 34 if(prime[i-2]==1) ans[i]=ans[i-1]+2; 35 else ans[i]=ans[i-1]+3; 36 } 37 } 38 } 39 int t;cin>>t; 40 while(t--) 41 { 42 int n; cin>>n; cout<<ans[n]<<endl; 43 } 44 }
D:摩天大楼
Description
随着科技的发展,某国家准备修建一座高楼,高度为n(n<=1e18),来展现他们国家的强大国力,他们国家有两支强大的施工队,国家于是把修建计划给了这两只施工队,为了提高施工队的积极性,国家会特殊奖励最后完成施工的,两只施工的施工计划是两只施工队轮流工作,由于施工队实力有限,每天只能修建1-m(m<=1e18)层,假如两只施工队都非常聪明,问首先施工的那只队伍能不能获得奖励,能输出YES,不能输出NO
Input
数据的组数 T;(T<=3000)
接下来T行,每行一个n m, 楼的高度,最大修建层数 (n,m<=1e18)
Output
每行一个单独的YES或者NO;Examples
Input
2
2 1
6 4
Output
NO
YES
正确解法:
两只队伍都非常聪明,知道如何使自己赢,每个人取的都是1~m个
无论第一支队伍取多少个,第二支队伍都能使两只队伍的和为1+m 个
故 n为m+1的倍数或者0时候,先手必输,其余先手必赢.
1 #include<bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 // freopen("cc.in","r",stdin); 6 // freopen("in.out","w",stdout); 7 long long n,m; 8 int t; cin>>t; 9 while(t--) 10 { 11 cin>>n>>m; 12 if(n%(m+1)==0) cout<<"NO"<<endl; 13 else cout<<"YES"<<endl; 14 } 15 }
E:招生
Description
浙江理工大学招生,一开始有0名学生报考,现在有如下几种情况;
1.增加一名报考学生,报考学生成绩为x;
2.一名成绩为x的学生放弃报考。
3.从现在报考的学生来看,老师想知道如果要招生至少x名学生,需要将分数线最高设置为多少;
4.从现在报考的学生来看,如果分数线设置为x,能有几名学生被录取。
第一行先输入一个n,表示有n次操作或查询;
接下来n行,每行输入两个整数opt和x(用空格隔开):
如果opt为1,则增加一名报考学生,报考学生成绩为x;
如果opt为2,则表示一名成绩为x的学生放弃报考。
如果opt为3,从现在报考的学生来看,老师想知道如果要招生至少x名学生,需要将分数线最高设置为多少,输出最高分数线。
如果opt为4,从现在报考的学生来看,如果分数线设置为x,能有几名学生被录取,输出录取人数。
对于每个输出占一行。
n不超过50000;0<=x<=1000000;1<=k<=现在的学生数。
Input
第一行输入一个n,接下来n行,每行输出两个整数opt,x,用空格隔开Output
对于每次输出, 输出一个整数占一行
Examples
Input
18
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
2 8
3 2
3 3
3 4
3 5
4 8
4 9
4 7
Output
11
10
9
7
4
4
5
正确解法:
平衡树treap
1 #include<bits/stdc++.h> 2 #define fi first 3 #define se second 4 #define INF 0x3f3f3f3f 5 #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) 6 #define pqueue priority_queue 7 #define NEW(a,b) memset(a,b,sizeof(a)) 8 const double pi=4.0*atan(1.0); 9 const double e=exp(1.0); 10 const int maxn=1e6+8; 11 typedef long long LL; 12 typedef unsigned long long ULL; 13 //typedef pair<LL,LL> P; 14 const LL mod=1e9+7; 15 const ULL base=1e7+7; 16 using namespace std; 17 struct node{ 18 int son[2]; 19 int siz; 20 int key,w; 21 }a[maxn]; 22 int tot=0; 23 int root=0,vis[maxn]; 24 void up(int i){ 25 a[i].siz=a[a[i].son[0]].siz+a[a[i].son[1]].siz+1; 26 } 27 void Rotate(int &i,int d){ 28 int t=a[i].son[d]; 29 a[i].son[d]=a[t].son[!d]; 30 a[t].son[!d]=i; 31 up(i);up(t); 32 i=t; 33 } 34 void Insert(int &i,int key){ 35 if(i==0){ 36 i=++tot; 37 a[i].siz=1;a[i].key=key;a[i].w=rand(); 38 return ; 39 } 40 a[i].siz++; 41 if(a[i].key>=key) { 42 Insert(a[i].son[0],key); 43 if(a[a[i].son[0]].w<a[i].w) Rotate(i,0); 44 } 45 else{ 46 Insert(a[i].son[1],key); 47 if(a[a[i].son[1]].w<a[i].w) Rotate(i,1); 48 } 49 } 50 void Del(int &i,int key){ 51 if(a[i].key==key){ 52 if(a[i].son[0]*a[i].son[1]==0) {i=a[i].son[0]+a[i].son[1];return ;} 53 if(a[a[i].son[0]].w>a[a[i].son[1]].w){ 54 Rotate(i,1); 55 Del(a[i].son[0],key); 56 } 57 else{ 58 Rotate(i,0); 59 Del(a[i].son[1],key); 60 } 61 } 62 else if(a[i].key>key){ 63 Del(a[i].son[0],key); 64 } 65 else{ 66 Del(a[i].son[1],key); 67 } 68 up(i); 69 } 70 int Find(int i,int key){ 71 if(i==0) return 1; 72 if(a[i].key>=key) return Find(a[i].son[0],key); 73 else return a[a[i].son[0]].siz+Find(a[i].son[1],key)+1; 74 } 75 int Search(int i,int rak){ 76 if(a[a[i].son[0]].siz==rak-1) return a[i].key; 77 if(a[a[i].son[0]].siz>=rak) return Search(a[i].son[0],rak); 78 else return Search(a[i].son[1],rak-a[a[i].son[0]].siz-1); 79 } 80 int pre(int i,int key){ 81 if(i==0) return -10000008; 82 if(a[i].key<key) return max(a[i].key,pre(a[i].son[1],key)); 83 return pre(a[i].son[0],key); 84 } 85 int bhe(int i,int key){ 86 if(i==0) return 10000008; 87 if(a[i].key>key) return min(a[i].key,bhe(a[i].son[0],key)); 88 return bhe(a[i].son[1],key); 89 } 90 int main(){ 91 int n; 92 freopen("data1.in","r",stdin); 93 freopen("data1.out","w",stdout); 94 scanf("%d",&n); 95 int opt,x; 96 int sum=0; 97 while(n--){ 98 scanf("%d%d",&opt,&x); 99 if(opt==1){ 100 Insert(root,x); 101 sum++; 102 vis[x]++; 103 } 104 if(opt==2){ 105 if(vis[x]){ 106 Del(root,x); 107 sum--; 108 vis[x]--; 109 } 110 } 111 if(opt==3){ 112 printf("%d ",Search(root,sum-x+1)); 113 } 114 if(opt==4){ 115 printf("%d ",sum-Find(root,x)+1); 116 } 117 } 118 }
F: 闲的无聊的简单题
Description
给你一个n*m的二维数组,a[i][j]表示第i行第j列的数字,现在求一个最大面积(长乘宽)的子矩形,要求对于该子矩形每一行中相邻的两个数,a[i][j]和a[i][j+1],存在一个整数k使得2的k次方同时小于等于a[i][j]和a[i][j+1],并且2的(k+1)次方大于a[i][j]和a[i][j+1],对于每一列中相邻的两个数,a[i][j]和a[i+1][j],不存在一个整数k使得2的k次方同时小于等于a[i][j]和a[i+1][j],并且2的(k+1)次方大于a[i][j]和a[i+1][j]。(0<n,m<=500)。Input
第一行输入两个数n,mOutput
输出一个表示符合要求的最大矩形面积
Examples
Input
4 4
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Output
6
描述:
对于样例,面积为6的矩形如下2 3
6 7
10 11
正确解法:
判断一个数a与另一个数b是否存在一个k满足可以用异或,令c=a^b,如果c同时小于a和b,则存在,否则则不存在。开三个数组up,l,r存每个点上边,左边和右边可以到达的最值,并且l和r不断更新,每次不断更新面积最大值即可。1 #include<bits/stdc++.h> 2 #define fi first 3 #define se second 4 #define INF 0x3f3f3f3f 5 #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) 6 #define pqueue priority_queue 7 #define NEW(a,b) memset(a,b,sizeof(a)) 8 const double pi=4.0*atan(1.0); 9 const double e=exp(1.0); 10 const int maxn=1e6+8; 11 typedef long long LL; 12 typedef unsigned long long ULL; 13 const LL mod=1e9+7; 14 const ULL base=1e7+7; 15 using namespace std; 16 int a[2008][2008]; 17 int l[2008][2008],r[2008][2008],u[2008][2008]; 18 int main(){ 19 //freopen("data5.in","r",stdin); 20 //freopen("data5.out","w",stdout); 21 int n,m; 22 scanf("%d%d",&n,&m); 23 for(int i=1;i<=n;i++){ 24 for(int j=1;j<=m;j++){ 25 scanf("%d",&a[i][j]); 26 } 27 l[i][1]=1;r[i][m]=m; 28 int k; 29 for(int j=2;j<=m;j++){ 30 k=a[i][j]^a[i][j-1]; 31 if(a[i][j]>=k&&a[i][j-1]>=k){ 32 l[i][j]=l[i][j-1]; 33 } 34 else{ 35 l[i][j]=j; 36 } 37 } 38 for(int j=m-1;j>=1;j--){ 39 k=a[i][j]^a[i][j+1]; 40 if(a[i][j]>=k&&a[i][j+1]>=k){ 41 r[i][j]=r[i][j+1]; 42 } 43 else{ 44 r[i][j]=j; 45 } 46 } 47 } 48 int maxa=0; 49 for(int i=1;i<=n;i++){ 50 for(int j=1;j<=m;j++){ 51 if(i>1&&(a[i][j]<(a[i][j]^a[i-1][j])||a[i-1][j]<(a[i][j]^a[i-1][j]))){ 52 u[i][j]=u[i-1][j]+1; 53 l[i][j]=max(l[i][j],l[i-1][j]); 54 r[i][j]=min(r[i][j],r[i-1][j]); 55 } 56 else{ 57 u[i][j]=1; 58 } 59 maxa=max(maxa,(r[i][j]-l[i][j]+1)*u[i][j]); 60 } 61 } 62 //cout<<u[39][17]<<endl; 63 cout<<maxa<<endl; 64 }
G: 简单题*10086
Description
现有N个数c1,c2,...,cN。对于每个数求有多少个有序二元组(i,j)满足以下式子
ci * cj mod P=ck(i,j,k可想等)
其中P为一给定质数。对于每个k对应的答案记为cnt[k],请你将每两个相邻的答案相加,这样答案总个数每次减少1,当答案个数为1时结束(结果对1e9+7取模)。为了感谢wjh、xxb、lmb、cly、ckx、yzj出了一堆简单题,请将他们名字缩写(小写)合并后去重并输出字典序第k大,k为所得结果乘上2333333后取模6666666的结果。
Input
第一行输入一个组数t(t ≤ 5)。Output
输出共一行,为对应答案的字典序排列(答案为0输出-1)。Examples
Input
2
7 3
1 2 3 4 5 6 7
5 7
1 0 2 3 0
Output
ckybhmwzxjl
byjlhwzmckx
正确解法:
例如答案是1 2 3 4 5那么你应该经过以下变化变成一个答案1 2 3 4 53 5 7 9
8 12 16
20 28
48
我们令g为质数P的原根,那么对于一个数字ai,唯一存在一个数字bi,使得 。那么我们把所有的ai用这种形式表示,于是对于原本的式子ci*cj≡ck(mod P),有,那么可以有bi+bj=bk。这样问题就从乘法变成了加法,FFT就可以排上用场了。而且你会发现,这里的bi的大小都是在P以内的。这样直接FFT即可,最后特殊处理一下0的情况即可。而对于接下来的一部可以发现最后结果就是C(n-1,0)*a[1]+C(n-1,1)*a[2]+……+C(n-1,n-1)*a[n],可以O(n)求出答案,最后一步是个逆康托展开。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <bitset> 5 #include <cmath> 6 #include <cctype> 7 #include <iostream> 8 #include <algorithm> 9 #include <string> 10 #include <vector> 11 #include <queue> 12 #include <map> 13 #include <set> 14 #include <sstream> 15 #include <iomanip> 16 using namespace std; 17 typedef long long ll; 18 typedef unsigned long long ull; 19 const ll inff = 0x3f3f3f3f3f3f3f3f; 20 #define FOR(i,a,b) for(int i(a);i<=(b);++i) 21 #define FOL(i,a,b) for(int i(a);i>=(b);--i) 22 #define REW(a,b) memset(a,b,sizeof(a)) 23 #define inf int(0x3f3f3f3f) 24 #define si(a) scanf("%d",&a) 25 #define sl(a) scanf("%lld",&a) 26 #define sd(a) scanf("%lf",&a) 27 #define ss(a) scanf("%s",a) 28 #define mod ll(6666666) 29 #define pb push_back 30 #define eps 1e-6 31 #define lc d<<1 32 #define rc d<<1|1 33 #define Pll pair<ll,ll> 34 #define P pair<int,int> 35 #define pi acos(-1) 36 ll n,p,g,id[2000008],m,ans[5000008],pr[1000008],prime[1000008],qw[1000008],tot; 37 ll a[100008],jc[15],inv[100008],mm=1e9+7,vis[15],sss[100008]; 38 char s[15],ss[5008]; 39 inline int read() 40 { 41 int X=0,w=0; char ch=0; 42 while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} 43 while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); 44 return w?-X:X; 45 } 46 void init(int n) 47 { 48 int i,j; 49 tot=0; 50 prime[1]=1; 51 for(i=2;i<=n;i++) 52 { 53 if(!prime[i]) prime[i]=pr[tot++]=i; 54 for(j=0;j<tot&&pr[j]*i<=n;j++) 55 { 56 prime[i*pr[j]]=pr[j]; 57 if(i%pr[j]==0) break; 58 } 59 } 60 } 61 ll gmod(ll a,ll b,ll p) 62 { 63 ll res=1; 64 while(b) 65 { 66 if(b&1) res=res*a%p; 67 a=a*a%p,b>>=1; 68 } 69 return res; 70 } 71 int root(int x) 72 { 73 int f,phi=x-1;qw[0]=0; 74 for(int i=0;phi&&i<tot;i++) 75 { 76 if(phi%pr[i]==0) 77 { 78 qw[++qw[0]]=pr[i]; 79 while(phi%pr[i]==0) phi/=pr[i]; 80 } 81 } 82 for(int g=2;g<=x-1;g++) 83 { 84 f=1; 85 for(int i=1;i<=qw[0];i++) 86 if(gmod(g,(x-1)/qw[i],x)==1) {f=0;break;} 87 if(f) return g; 88 } 89 return 0; 90 } 91 struct CP{ 92 double x,y; 93 CP(){} CP(double a,double b):x(a),y(b){} 94 CP operator+(const CP&r) const{return CP(x+r.x,y+r.y);} 95 CP operator-(const CP&r) const{return CP(x-r.x,y-r.y);} 96 CP operator*(const CP&r) const{return CP(x*r.x-y*r.y,x*r.y+y*r.x);} 97 }b[5000008],t; 98 inline void Swap(CP&a,CP&b) {t=a;a=b;b=t;} 99 inline void fft(CP*a,int f,int n) 100 { 101 int i,j,k; 102 for(i=j=0;i<n;i++) 103 { 104 if(i>j) Swap(a[i],a[j]); 105 for(k=n>>1;(j^=k)<k;k>>=1); 106 } 107 for(int i=1;i<n;i<<=1) 108 { 109 CP wn(cos(pi/i),f*sin(pi/i)); 110 for(int j=0;j<n;j+=i<<1) 111 { 112 CP w(1,0); 113 for(int k=0;k<i;k++,w=w*wn) 114 { 115 CP x=a[j+k],y=w*a[i+j+k]; 116 a[j+k]=x+y;a[i+j+k]=x-y; 117 } 118 } 119 } 120 if(f==-1) FOR(i,0,n) a[i].x/=n; 121 } 122 void rkt(ll n,ll k) 123 { 124 ll t,ty=0; 125 REW(vis,0); 126 n--; 127 FOR(i,0,k-1) 128 { 129 t=n/jc[k-i-1]; 130 n%=jc[k-i-1]; 131 for(ll j=0,pos=0;;j++,pos++) 132 { 133 if(vis[pos]) j--; 134 if(j==t){vis[pos]=1;s[ty++]=('a'+pos+1);break;} 135 } 136 } 137 } 138 int main() 139 { 140 cin.tie(0); 141 cout.tie(0); 142 freopen("date1.in","r",stdin); 143 freopen("date1.out","w",stdout); 144 int tt; 145 cin>>tt; 146 ss['b']='b',ss['c']='c',ss['d']='h',ss['e']='j',ss['f']='k',ss['g']='l'; 147 ss['h']='m',ss['i']='w',ss['j']='x',ss['k']='y',ss['l']='z'; 148 jc[0]=jc[1]=1; 149 for(ll i=2;i<=12;i++) jc[i]=jc[i-1]*i; 150 inv[1]=1; 151 FOR(i,2,100005) inv[i]=(mm-mm/i)*inv[mm%i]%mm; 152 init(100000); 153 while(tt--) 154 { 155 cin>>n>>p; 156 g=root(p); 157 ll tmp=1,qw=0,er,sum=1; 158 for(int i=1;i<p-1;i++) 159 { 160 tmp=tmp*g%p; 161 id[tmp]=i; 162 } 163 er=m=p-1; 164 for(m=er+m,er=1;er<=m;er<<=1); 165 FOR(i,0,er+1) b[i].x=b[i].y=0.0,ans[i]=0; 166 FOR(i,1,n) 167 { 168 a[i]=read(); 169 if(!(a[i]%p)) qw++; 170 else b[id[a[i]%p]].x+=1.0; 171 } 172 fft(b,1,er); 173 FOR(i,0,er) b[i]=b[i]*b[i]; 174 fft(b,-1,er); 175 for(int i=0;i<2*p;i++) ans[i%(p-1)]+=(ll)(b[i].x+0.2); 176 for(int i=1;i<=n;i++) 177 { 178 if(a[i]>=p) er=0; 179 else if (a[i]==0) er=2*qw*n-qw*qw; 180 else er=ans[id[a[i]]]; 181 sss[i]=er; 182 } 183 er=0; 184 for(int i=0;i<n;i++) 185 { 186 er=(er+sum*sss[i+1])%mm; 187 sum=(sum*(n-1-i)%mm)*inv[i+1]%mm; 188 } 189 //cout<<er<<endl; 190 er=((er%mod)*2333333)%mod; 191 if(er==0) {puts("-1");continue;} 192 rkt(er,11); 193 for(int i=0;i<11;i++) printf("%c",ss[s[i]]); 194 puts(""); 195 } 196 return 0; 197 }
H: 简单题*10000
Description
已知一排硬币中有n个硬币正面朝上,输入正面朝上的硬币的位置ai(可能重复)。Input
第一行输入一个组数t(t ≤ 100)。
对于每组数据第一行有一个正整数N(0 ≤ N ≤ 5000)。
第二行N个非负整数c1,c2,...,cN(0 ≤ ai ≤ 1e9)。
Output
如果先手必胜输出Yes,否则输出No。
Examples
Input
2
1
0
4
0 1 2 3
Output
Yes
No
正确解法:
定义硬币全反时的sg为0,现在单个游戏就是只有一枚硬币朝上,其余都是反,其他情况都可以由单一游戏组合而成。如果位置i有一个正面朝上的硬币,其余都是反,那么这枚硬币翻过来的时候,它可以到达的局面是1、sg = 0 2、sg(j)j位置的硬币朝上,其余都是反(j<i) 3、出现两个正面朝上的硬币,变成组合游戏sg(j)和sg(k)。我们把sg函数打表出来就可以找到规律。(hdu3537)
初始编号从0开始。
当N==1时,硬币为:正,先手必胜,所以sg[0]=1.
当N==2时,硬币为:反正,先手必赢,先手操作后可能为:反反或正反,方案数为2,所以sg[1]=2。
当N==3时,硬币为:反反正,先手必赢,先手操作后可能为:反反反、反正反、正反正、正正反,方案数为4,所以sg[2]=4。
位置x:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14...
sg[x]: 1 2 4 7 8 11 13 14 16 19 21 22 25 26 28…
看上去sg值为2x或者2x+1。我们称一个非负整数为odious,当且仅当该数的二进制形式的1出现的次数是奇数,否则称作evil。所以1,2,4,7是odious因为它们的二进制形式是1,10,100,111.而0,3,5,6是evil,因为它们的二进制形式是0,11,101,110。而上面那个表中,貌似sg值都是odious数。所以当2x为odious时,sg值是2x,当2x是evil时,sg值是2x+1.
这样怎么证明呢?我们会发现发现,
evil^evil=odious^odious=evil
evil^odious=odious^evil=odious
假设刚才的假说是成立的,我们想证明下一个sg值为下一个odious数。注意到我们总能够在第x位置翻转硬币到达sg为0的情况;通过翻转第x位置的硬币和两个其它硬币,我们可以移动到所有较小的evil数,因为每个非零的evil数都可以由两个odious数异或得到;但是我们不能移动到下一个odious数,因为任何两个odious数的异或都是evil
假设在一个Mock Turtles游戏中的首正硬币位置x1,x2,…,xn是个P局面,即sg[x1]^…^sg[xn]=0.那么无可置疑的是n必定是偶数,因为奇数个odious数的异或是odious数,不可能等于0。而由上面可知sg[x]是2x或者2x+1,sg[x]又是偶数个,那么x1^x2^…^xn=0。相反,如果x1^x2^…^xn=0且n是偶数,那么sg[x1]^…^sg[xn]=0。这个如果不太理解的话,我们可以先这么看下。2x在二进制当中相当于把x全部左移一位,然后补零,比如说2的二进制是10,那么4的二进制就是100。而2x+1在二进制当中相当于把x全部左移一位,然后补1,比如说2的二进制是10,5的二进制是101。现在看下sg[x1]^…^sg[xn]=0,因为sg[x]是2x或者2x+1,所以式子中的2x+1必须是偶数个(因为2x的最后一位都是0,2x+1的最后一位都是1,要最后异或为0,2x+1必须出现偶数次)
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <bitset> 5 #include <cmath> 6 #include <cctype> 7 #include <iostream> 8 #include <algorithm> 9 #include <string> 10 #include <vector> 11 #include <queue> 12 #include <map> 13 #include <set> 14 #include <sstream> 15 #include <iomanip> 16 using namespace std; 17 typedef long long ll; 18 typedef unsigned long long ull; 19 const ll inff = 0x3f3f3f3f3f3f3f3f; 20 #define FOR(i,a,b) for(int i(a);i<=(b);++i) 21 #define FOL(i,a,b) for(int i(a);i>=(b);--i) 22 #define REW(a,b) memset(a,b,sizeof(a)) 23 #define inf int(0x3f3f3f3f) 24 #define si(a) scanf("%d",&a) 25 #define sl(a) scanf("%lld",&a) 26 #define sd(a) scanf("%lf",&a) 27 #define ss(a) scanf("%s",a) 28 #define mod ll(6666666) 29 #define pb push_back 30 #define eps 1e-6 31 #define lc d<<1 32 #define rc d<<1|1 33 #define Pll pair<ll,ll> 34 #define P pair<int,int> 35 #define pi acos(-1) 36 int n,a[100008]; 37 int as(int x) 38 { 39 int k=0; 40 while (x) 41 { 42 if (x&1) k++; 43 x>>=1; 44 } 45 return !(k&1); 46 } 47 int main() 48 { 49 cin.tie(0); 50 cout.tie(0); 51 //freopen("game001.in","r",stdin); 52 //freopen("game001.out","w",stdout); 53 int tt; 54 cin>>tt; 55 while(tt--) 56 { 57 si(n); 58 FOR(i,1,n) si(a[i]); 59 sort(a+1,a+n+1); 60 int k=unique(a+1,a+n+1)-a-1,s=0; 61 FOR(i,1,k) 62 { 63 a[i]*=2ll; 64 if(as(a[i])) a[i]++; 65 s^=a[i]; 66 } 67 if(s) puts("Yes"); 68 else puts("No"); 69 } 70 return 0; 71 }
I: 水题
Description
史努比最爱水题了,他知道现在他要挑战的是一道超级大水题哦。不过因为太水了,而且他又很懒,所以把这道水题推给了你们。
有n个(不包括ZSTU和火车东站)车站介于ZSTU和火车东站之间,一共有m辆公交车往返于这些车站和火车东站。每个车站假设可以站无数个人,每辆车最多承载H[i]个人,经过S[i]个车站。假设一辆车依次经过1,2,3,这三个车站,那么它将一直往复1->2->3->1->2...现在认为车从一个站到下一个站要花费1个小时,人只能在车站或ZSTU,火车东站上下车,初始时有k个人在ZSTU(0站),所有的车都在初始站(所给车站的第一个车站为初始站),现在问你们最快让全部人从ZSTU到火车东站要多少小时。所有车同时运行。
Input
第一行有一个T<=10,表示T组测试样例,第二行三个数n(车站数目),m(车数目),k(人数),(n<=13,m<=20,k<=50);接下来的m行给出车信息,每行给出H[i](能承载的最大人数),S[i](经过的车站数目),还有依次给出S[i]个车站编号。ZSTU用0编号表示,火车东站用-1表示。Output
若无解则输出-1,否则逐行输出答案。Examples
Input
2
2 2 1
1 3 0 1 2
1 3 1 2 -1
2 3 3
1 2 0 2
1 2 1 2
1 2 1 -1
Output
5
7
正确解法:
第一个样例,一人从0站乘坐1号公交车途径1站,到2站下车,花费2S;此时2号车位于-1站,再经过2S,2号车从-1站途径1站到2站,人上2号车再经过1S到达-1站,共花费5S。或者一人从0站乘坐一号公交车到1站下车,花费1S,此时2号车位于2站,再经过2S到1站,人上2号车再经过2S到达-1站,共花费5S。
首先判断学校到火车东站能不能到站,即是否在同一个集团里面,用并查集就可以了。然后跑网络流,网络流跑一次后会更改原来储存的边的信息,因此可以枚举时间进行网络流,按照时间建边,在上一个时间段跑网络流的基础上,继续建图在继续跑网络流,将每次的最大流加起来直到总和大于等于k就可以返回当前天数了。
具体操作是将第i-1小时的第j个车的信息向第i小时的第j个车进行连边,容量为INF,将每辆车第i-1小时所待的公交车站向第i小时所待的公交车站连边,容量为车的最大载人数。
1 #include <bits/stdc++.h> 2 //CLOCKS_PER_SEC 3 #define se second 4 #define fi first 5 #define ll long long 6 #define lson l,m,rt<<1 7 #define rson m+1,r,rt<<1|1 8 #define Pii pair<int,int> 9 #define Pli pair<ll,int> 10 #define ull unsigned long long 11 #define pb push_back 12 #define fio ios::sync_with_stdio(false);cin.tie(0) 13 const double Pi=3.14159265; 14 const int N=1e3+5; 15 const ull base=163; 16 const int INF=0x3f3f3f3f; 17 using namespace std; 18 int n,m,k,s,t; 19 int head[10100],to[100010],cur[10100],nx[100010]; 20 int cap[100010]; 21 int tot=0; 22 void add(int x,int y,int c){ 23 to[tot]=y; 24 nx[tot]=head[x]; 25 cap[tot]=c; 26 head[x]=tot++; 27 28 to[tot]=x; 29 nx[tot]=head[y]; 30 cap[tot]=0; 31 head[y]=tot++; 32 } 33 void init(int n){ 34 tot=0; 35 memset(head,-1,sizeof(head)); 36 } 37 int d[N]; 38 int bfs(){ 39 memset(d,-1,sizeof(d)); 40 queue<int>q; 41 q.push(s); 42 d[s]=1; 43 while(!q.empty()){ 44 int u=q.front();q.pop(); 45 for(int i=head[u];~i;i=nx[i]){ 46 int v=to[i]; 47 if(d[v]==-1&&cap[i]>0){ 48 d[v]=d[u]+1; 49 q.push(v); 50 } 51 } 52 } 53 return d[t]!=-1; 54 } 55 int dfs(int s,int a){ 56 if(s==t||a==0)return a; 57 int flow=0,f; 58 for(int &i=cur[s];~i;i=nx[i]){ 59 int v=to[i]; 60 if(d[s]+1==d[v] && cap[i]>0 && (f=dfs(v,min(a,cap[i])))>0){ 61 flow+=f; 62 cap[i]-=f; 63 cap[i^1]+=f; 64 a-=f; 65 if(a==0)break; 66 } 67 } 68 return flow; 69 } 70 int dinic(){ 71 int ans=0; 72 while(bfs()){ 73 for(int i=0;i<=1000;i++)cur[i]=head[i]; 74 while(int di=dfs(s,INF)){ 75 ans+=di; 76 } 77 } 78 return ans; 79 } 80 int ship[N][N]; 81 int num[N]; 82 int r[N]; 83 int fa[N]; 84 int F(int x){ 85 return fa[x]==x?x:fa[x]=F(fa[x]); 86 } 87 88 bool check(int x,int y){ 89 if(F(x)==F(y))return 1; 90 else return 0; 91 } 92 int cal(int a,int d){ 93 return d*n+a; 94 } 95 void solve(){ 96 int flow=0; 97 int i; 98 init(n);// n -1 n-1 0 99 add(s,cal(n-1,0),INF); 100 add(cal(n,0),t,INF); 101 for(i=1;flow<k;i++){ 102 add(s,cal(n-1,i),INF);add(cal(n,i),t,INF); 103 for(int j=1;j<=n;j++){ 104 add(cal(j,i-1),cal(j,i),INF); 105 } 106 for(int j=1;j<=m;j++){ 107 int a=(i-1)%num[j]+1; 108 int b=i%num[j]+1; 109 add(cal(ship[j][a],i-1),cal(ship[j][b],i),r[j]); 110 } 111 flow+=dinic(); 112 113 } 114 printf("%d ",i-1); 115 } 116 int main(){ 117 // clock_t start, end; 118 int T;scanf("%d",&T); 119 while(T--){ 120 s=0,t=1000; 121 scanf("%d%d%d",&n,&m,&k); 122 for(int i=0;i<=n+2;i++)fa[i]=i; 123 for(int i=1;i<=m;i++){ 124 scanf("%d%d",&r[i],&num[i]); 125 for(int j=1;j<=num[i];j++){ 126 scanf("%d",&ship[i][j]); 127 if(ship[i][j]==0)ship[i][j]=n+1; 128 if(ship[i][j]==-1)ship[i][j]=n+2; 129 if(j>1){ 130 fa[F(ship[i][j-1])]=F(ship[i][j]); 131 } 132 } 133 } 134 n+=2; 135 if(check(n, n-1)){ 136 solve(); 137 } 138 else{ 139 printf("0 "); 140 } 141 } 142 // end = clock(); 143 // cout << "time :"<<(double)(end - start) / CLOCKS_PER_SEC << endl; 144 return 0; 145 } 146 /* 147 */
K: 快乐树论
Description
曾经有一位伟大的皇帝,他拥有n座城池并用n-1条无向道路相连,每条道路均有一个确定的长度和两个端点,保证城池与城池之间互达。有一天,皇帝决定将其中一条路拆掉,并重新将这条道路以同样的长度搭在两座城池之间,皇帝可能将这条路拆了又重新建在原处。现在皇帝想问问你,在只拆掉一条道路并重新建造一条同样长的在两座城池之间后,任意两个城池之前的距离和最小为多少呢?Input
第一行输入一个n代表皇帝有n座城池,接下来n-1行输入a,b,c代表城池a,b之间有一条长为c的道路。 (2 ≤ n ≤ 5000, 1 ≤ ai, bi ≤ n, ai ≠ bi, 1 ≤ wi ≤ 106)
Output
输出一行任意两城池之间的最小距离和。
Examples
Input
输入样例1:
3
1 2 2
1 3 4
输入样例2:
6
1 2 1
2 3 1
3 4 1
4 5 1
5 6 1
输入样例3:
6
1 3 1
2 3 1
Output
12
29
85
正确解法:
具体证明参考:https://blog.csdn.net/zhoufenqin/article/details/9821617
1 #include<bits/stdc++.h> 2 3 #define fi first 4 #define se second 5 #define pb push_back 6 7 using namespace std; 8 9 typedef long long ll; 10 typedef pair<ll,ll> Pll; 11 12 const ll LLMAX=2e18; 13 const int MAXN=1e6+10; 14 15 struct node{ 16 int u,v; 17 ll w; 18 }in[MAXN]; 19 20 ll dp[MAXN][3]; 21 vector<Pll>G[MAXN]; 22 23 void dfs(int u,int pre){ 24 dp[u][0]=dp[u][1]=dp[u][2]=0; 25 for(int i=0;i<G[u].size();i++){ 26 int v=G[u][i].fi,w=G[u][i].se; 27 if(v==pre) continue; 28 dfs(v,u); 29 dp[u][2]+=dp[v][2]+dp[v][1]*dp[u][0]+dp[v][0]*dp[u][1]+dp[u][0]*dp[v][0]*w; 30 dp[u][1]+=dp[v][1]+dp[v][0]*w; 31 dp[u][0]+=dp[v][0]; 32 } 33 dp[u][0]++; 34 dp[u][2]+=dp[u][1]; 35 } 36 37 void solve(int u,int pre,ll &ans){ 38 ans=min(ans,dp[u][1]); 39 for(int i=0;i<G[u].size();i++){ 40 int v=G[u][i].fi,w=G[u][i].se; 41 if(v==pre) continue; 42 dp[v][1]=dp[v][1]+(dp[u][1]-dp[v][1]-w*dp[v][0])+(dp[u][0]-dp[v][0])*w; 43 dp[v][0]=dp[u][0]; 44 solve(v,u,ans); 45 } 46 } 47 48 int main(void) 49 { 50 ios::sync_with_stdio(false); cin.tie(0); 51 ll n,ans=LLMAX; cin>>n; 52 for(int i=1;i<n;i++){ 53 ll x,y,v; cin>>x>>y>>v; 54 in[i].u=x,in[i].v=y,in[i].w=v; 55 G[x].pb(Pll(y,v)),G[y].pb(Pll(x,v)); 56 } 57 for(int i=1;i<n;i++){ 58 ll ans1=LLMAX,ans2=LLMAX,u=in[i].u,v=in[i].v,w=in[i].w; 59 dfs(u,v); solve(u,v,ans1); 60 ll len1=(n-dp[u][0])*ans1+dp[u][2]; 61 dfs(v,u); solve(v,u,ans2); 62 ll len2=(n-dp[v][0])*ans2+dp[v][2]; 63 ans=min(ans,len1+len2+dp[u][0]*dp[v][0]*w); 64 } 65 cout<<ans<<endl; 66 return 0; 67 }
L: 快乐数论
Description
给出正整数n,k,要求使正整数n拆分成若干个正整数的和,并且使得拆分后的数中相同的数的出现次数小于k次。Input
第一行输入T,共有T组测试样例,接下来2~T+1行,每行输入n,k。 1<=n,k,T<=10^5
Output
输出T行,每行对应的拆分方案,最后答案取模1e9+7
Examples
Input
4
4 2
4 3
4 4
4 5
Output
2
4
4
5
正确解法:
n=4,k=2时,可拆分成4=4,4=1+3
n=4,k=3时,可拆分成4=1+2+1,4=2+2,4=1+3,4=4
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int MOD=1e9+7; 8 const int MAXN=1e6+10; 9 10 ll p[MAXN]; 11 12 void init(){ 13 p[0]=1; 14 for(ll i=1;i<=100000;i++){ 15 for(ll j=1,w=1;w<=i;j++,w=(3*j*j+j)/2) 16 if(j&1) p[i]=(p[i]+p[i-w])%MOD; 17 else p[i]=((p[i]-p[i-w])%MOD+MOD)%MOD; 18 for(ll j=1,w=2;w<=i;j++,w=(3*j*j-j)/2) 19 if(j&1) p[i]=(p[i]+p[i-w])%MOD; 20 else p[i]=((p[i]-p[i-w])%MOD+MOD)%MOD; 21 } 22 } 23 24 ll solve(ll n,ll k){ 25 ll ans=p[n]; 26 for(ll j=1,w=k;w<=n;j++,w=k*(3*j*j+j)/2) 27 if(j&1) ans=((ans-p[n-w])%MOD+MOD)%MOD; 28 else ans=(ans+p[n-w])%MOD; 29 for(ll j=1,w=2*k;w<=n;j++,w=k*(3*j*j-j)/2) 30 if(j&1) ans=((ans-p[n-w])%MOD+MOD)%MOD; 31 else ans=(ans+p[n-w])%MOD; 32 return ans; 33 } 34 35 int main(void) 36 { 37 init(); 38 int T; cin>>T; 39 while(T--){ 40 ll n,k; scanf("%lld%lld",&n,&k); 41 printf("%lld ",solve(n,k)); 42 } 43 return 0; 44 }
M: 看电影
Description
wjh要去看电影,邀请了lmb,xxb,cly,yzj,ckx等人,最后有k个人同意一起去。要去的电影院的位置是矩阵型的,其中’#’表示已经被人预定了,’*’表示空位,他们打算挑同一行或者同一列连续的座位坐在一起,现在给出k和位置的预定请况,试问有几种坐位置的方法。Input
第一行输入两个数n和k,n表示电影院的位置是n*n的。(0<n<=10,0<=k<10)Output
一行输出有几种坐法。Examples
Input
4 1
**##
*###
####
####
Output
4
正确解法:
暴力纵向横向搜索一下。
当k为0时,答案要除2。