Chaos Begin 题目大意 二维平面上有两组点,每组有n个点,其中
但现在不知道点属于a,b哪个集合,需要你找出所有可能的
解题思路 先对所有2n个点排序,那么一定包含于最小的两个点开始与所有点做差的所有情况中。
由于点对完全随机,所以可以直接这样遍历上面所有情况找到符合的作为答案。时间复杂度会被降到nlogn(因为有不符合直接剪纸处理)
假设为可能的答案,我们只需要先把所有点存入map计数,然后从小到大扫一遍,如果这个点的数量大于等于0,那么就找是否有这个点加上后还有跟它匹配的点。没有则直接剪纸,有则接着往后找。
参考代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #include <bits/stdc++.h> using namespace std;using i64 = long long ;#define endl '\n' bool multi=1 ;void solve () { int n; cin >> n; n *= 2 ; vector<pair<int , int >> p (n); for (int i = 0 ; i < n; i++){ cin >> p[i].first >> p[i].second; } sort (p.begin (), p.end ()); map<pair<int , int >, int > f; vector<pair<int , int >> ans; for (auto v:p) f[v]++; for (int i = 1 ; i < n; i++){ int dx = p[i].first - p[0 ].first, dy = p[i].second - p[0 ].second; vector<pair<int , int >> tmp; bool flag = 0 ; for (int j = 0 ; j < n; j++){ if (f[p[j]]){ if (f[{p[j].first + dx, p[j].second + dy}]){ f[{p[j].first + dx, p[j].second + dy}]--; f[p[j]]--; tmp.push_back ({p[j].first + dx, p[j].second + dy}); tmp.push_back (p[j]); }else { flag = 1 ; break ; } } } if (!flag){ ans.push_back ({dx, dy}); ans.push_back ({-dx,-dy}); } for (auto it:tmp) f[it]++; } sort (ans.begin (), ans.end ()); ans.erase (unique (ans.begin (), ans.end ()), ans.end ()); cout << ans.size () << '\n' ; for (auto it:ans){ cout << it.first << ' ' << it.second << '\n' ; } } signed main () { ios::sync_with_stdio (false );cin.tie (0 );cout.tie (0 ); int T=1 ; if (multi) cin>>T; while (T--){ solve (); } return 0 ; }
Out of Control 题目大意 给定n个时间戳,最初栈为空,当接受一个时间戳信号会附加在堆栈末尾,若这个时间戳比之前的末尾小,那么这个时间戳会变成上一个时间戳。但由于网失控,使得可能会以任意顺序接收请求且可能错过某些请求,现在问你堆栈数量分别为1~n时的可能情况的数量。
解题思路 先进行离散化处理记录每个数的数量和前缀数量。
下面的j结尾都指的是离散化后的值。
定义为堆栈数量为i的情况中,以1~j为堆栈结尾的方案数。
那么它一定能从转移过来,因为j从1遍历到tot(离散化后的总数),那么1~j-1结尾的堆栈数量为i-1的数列后末尾都可以加上j变成堆栈数量为i的以j结尾的数列。
而i-1个堆栈数量以j结尾的数加上一个小于等于j的数,判断前j个数数量是否大于等于i即能不能找到多余出来的小于等于j的数,如果能就从转移过来。
剩下的就是从转移过来。
最后的答案就是
复杂度分析 时间复杂度:O(n^2)
参考代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 #include <bits/stdc++.h> using namespace std;#define endl '\n' #define debug(a) cout<<#a<<"=" <<a<<endl; #define int long long #define x1 x111111 #define y1 y111111 #define x0 x00000 #define y0 y00000 typedef long long LL;typedef pair<int ,int > PII;const double eps=1e-8 ;const int mod=1e9 +7 ;bool multi=1 ;const int N=3010 ;int n,a[N];int dp[N][N];int b[N];int sum[N];void solve () { cin>>n; for (int i=1 ;i<=n;i++){ for (int j=1 ;j<=n;j++){ dp[i][j]=0 ; } } map<int ,int > mp; for (int i=1 ;i<=n;i++){ cin>>a[i]; mp[a[i]]++; } int tot=0 ; for (auto it:mp){ b[++tot]=it.second; } for (int i=1 ;i<=tot;i++){ sum[i]=0 ; } for (int i=1 ;i<=tot;i++){ sum[i]=sum[i-1 ]+b[i]; } for (int i=1 ;i<=n;i++){ dp[1 ][i]+=dp[1 ][i-1 ]+(i<=tot); } for (int i=2 ;i<=n;i++){ for (int j=1 ;j<=tot;j++){ dp[i][j]=(dp[i][j]+dp[i-1 ][j-1 ])%mod; if (sum[j]>=i)dp[i][j]=((dp[i][j]+dp[i-1 ][j]-dp[i-1 ][j-1 ])%mod+mod)%mod; dp[i][j]=(dp[i][j]+dp[i][j-1 ])%mod; } } for (int i=1 ;i<=n;i++){ cout<<(dp[i][tot]%mod+mod)%mod<<endl; } } signed main () { ios::sync_with_stdio (false );cin.tie (0 );cout.tie (0 ); int TTT=1 ; if (multi) cin>>TTT; while (TTT--){ solve (); } return 0 ; }
8-bit Zoom 题目大意 给定一个图片,由n*n个字符组成,告诉你缩放比率Z,若能缩放输出缩放后的图片,若不能缩放输出error。
当100|n*Z不满足时,或缩放前无法确定某些像素的颜色,图片不能被缩放。
解题思路 dfs模拟即可。判断一下不能整除或者缩放前像素有多个颜色的清理。
当Z=100时,图片不变;当Z=125时,每个相同的颜色变成个相同的颜色;当Z=150时,每个相同的颜色变成个相同的颜色;当Z=175时,每个相同的颜色变成个相同的颜色;当Z=200时,每个相同的颜色变成个相同的颜色.
复杂度分析 时间复杂度:O(n^2)
参考代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 #include <bits/stdc++.h> using namespace std;#define endl '\n' #define debug(a) cout<<#a<<"=" <<a<<endl; #define int long long #define x1 x111111 #define y1 y111111 #define x0 x00000 #define y0 y00000 typedef long long LL;typedef pair<int ,int > PII;const double eps=1e-8 ;bool multi=1 ;const int N=210 ;char s[N][N];char res[N][N];bool suc;int ed;map<int ,int > mp1={{100 ,1 },{125 ,4 },{150 ,2 },{175 ,4 },{200 ,1 }},mp2={{100 ,1 },{125 ,5 },{150 ,3 },{175 ,7 },{200 ,2 }}; int n,Z;void dfs (int x1,int y1,int x2,int y2,int Z) { if (suc==0 ) return ; if (y1>n){ ed=max (x2,y2); return ; }else if (x1>n){ dfs (1 ,y1+mp1[Z],1 ,y2+mp2[Z],Z); return ; }else { dfs (x1+mp1[Z],y1,x2+mp2[Z],y2,Z); } for (int i=x1;i<=x1+mp1[Z]-1 ;i++){ for (int j=y1;j<=y1+mp1[Z]-1 ;j++){ if (s[i][j]!=s[x1][y1]){ suc=0 ; return ; } } } for (int i=x2;i<=x2+mp2[Z]-1 ;i++){ for (int j=y2;j<=y2+mp2[Z]-1 ;j++){ res[i][j]=s[x1][y1]; } } } void solve () { cin>>n>>Z; suc=1 ; for (int i=1 ;i<=n;i++){ scanf ("%s" ,s[i]+1 ); } if (n*Z%100 !=0 ){ cout<<"error" <<endl; return ; } dfs (1 ,1 ,1 ,1 ,Z); if (suc==0 ){ cout<<"error" <<endl; return ; } for (int i=1 ;i<=ed-1 ;i++){ for (int j=1 ;j<=ed-1 ;j++){ cout<<res[i][j]; } cout<<endl; } } signed main () { int TTT=1 ; if (multi) cin>>TTT; while (TTT--){ solve (); } return 0 ; }
Noblesse Code 题目大意 给定n个(a[i],b[i]),接着有q个询问,每次给你(A[i],B[i]),你可以进行任意数量操作,每次操作可以使(A[i],B[i])变成(A[i]+B[i],B[i])或(A[i],A[i]+B[i]),对于每个询问,在n个二元组a,b中,求出有多少个可以通过(A[i],B[i])变换得到。
解题思路 首先我们会发现,(A[i],B[i])向上操作是不固定的,每层会以指数级情况增加,所以我们考虑(a[i],b[i])向下操作,当a[i]>b[i]时,a[i]=a[i]-b[i];当a[i]<b[i]时,b[i]=b[i]-a[i],若统计每个(a[i],b[i])所有出现的情况复杂度太高,如(1,1e18)每次只会向下减1,复杂度O(1e18)。
此时我们考虑优化,观察到例如a[i]<b[i]的情况中,(a[i],b[i])向下减,最终b[i]会变成a[i]%b[i],令这种情况称为拐点,那么我们可以记录每个拐点的情况mp[a[i],a[i]%b[i]].push_back(a[i]);然后对于询问(A[i],B[i]),分情况二分mp即可。
例如:(2,9)->(2,7)->(2,5)->(2,3)->(2,1)->(1,1)此时(2,1)就是一个拐点,mp[{2,1}].push_back(9);
当询问出现(2,5)时二分mp[{2,5%2}]这个vector中大于5的数,为什么这样可以呢?
因为这里就取模2就体现了能到{2,1}的位置一定是从1向上递增2的顺序上去或者从2每次递增1的顺序上去。
那么mp[{2,5%2}]这个容器中大于5的数有两种情况,一种是mp[{2,1}]中(2+k,1)左边递减下来到拐点记录但这种情况不存在,因为(2+k)%1最终的数必然小于1,另一种(2,1+2k)右边递减下来到拐点被记录,这两种情况只有一种情况存在,而询问(2,5)时,我们只需二分它下来的拐点(2,1)的vector容器就可以看有多少个(2,5),(2,7),(2,9)..来计算结果。
复杂度分析 时间复杂度:
参考代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <bits/stdc++.h> using namespace std;#define endl '\n' #define debug(a) cout<<#a<<"=" <<a<<endl; #define int long long typedef long long LL;typedef pair<int ,int > PII;typedef pair<double ,double > PDD;const double eps=1e-8 ;bool multi=1 ;const int N=1e5 +10 ;void solve () { int n,q; cin>>n>>q; map<PII,vector<int >> mp; for (int i=0 ;i<n;i++){ int x,y; cin>>x>>y; while (x>0 &&y>0 ){ if (x>=y){ int tx=x%y; mp[{tx,y}].push_back (x); x=tx; }else { int ty=y%x; mp[{x,ty}].push_back (y); y=ty; } } } for (auto &it:mp){ sort (it.second.begin (),it.second.end ()); } auto calc=[&](int x,int y,int c){ auto &v=mp[{x,y}]; return (int )distance (lower_bound (v.begin (),v.end (),c),v.end ()); }; for (int i=0 ;i<q;i++){ int x,y; cin>>x>>y; int ans=0 ; if (x>y) ans=calc (x%y,y,x); else if (x<y) ans=calc (x,y%x,y); else ans=calc (0 ,y,y)+calc (x,0 ,x); cout<<ans<<endl; } } signed main () { ios::sync_with_stdio (false );cin.tie (0 );cout.tie (0 ); int TTT=1 ; if (multi) cin>>TTT; while (TTT--){ solve (); } return 0 ; }