补题*总结题21/8/26
总结与经验
c++输入带空格字符串方式cin.getline
cin.getline(接受的字符串,接受个数,结束标志)
当第三个参数省略时,系统默认为'\0' 是‘/n’。
两点间距离新思路:(三角形两边之差小于第三边)
I - Odd Gnome(水题)
Canonical Coin Systems(多重背包+贪心)
题意:
给一组货币a[1] ~ a[n]。求买 1 ~2 × a[n] 价值的商品,用该组货币,使用贪心算法(每次挑选最大面额货币),是不是使用货币最少的解
思路:
用多重背包问题的dp求出正确解,
验证贪心是否正确
错误代码:
展开代码
#include <bits/stdc++.h> using namespace std; #define ll long long /* 如果 S 是非规范的, 那么最小的反例小于两个最大面额的总和。 */ int dp[20000001]; int main() { int n; cin>>n; int a[n+1]; int i,j; for(i=1; i<=n; i++) { cin>>a[i]; } int max_data=a[n]+a[n]; memset(dp,0,sizeof(dp)); int flag=1; for(i=1; i<=n; i++) { for(j=max_data; j>=a[i]; j--) { if(i==1) { dp[j]=j/a[i]; } else { int t=j/a[i]; int o=dp[ j-t*a[i] ]+t; dp[j]=min(o,dp[j]); if(dp[j]!=o)//错误原因 { flag=0; break; } } } if(flag==0 ) { break; } } if(flag==1 ) cout<< "canonical" << endl; else cout<< "non-canonical" << endl; return 0; }
错误原因:
int t=j/a[i]; int o=dp[ j-t*a[i] ]+t; dp[j]=min(o,dp[j]); if(dp[j]!=o)//错误原因 { flag=0; break; }
以为这样就能模拟贪心
正确代码:
#include <bits/stdc++.h> using namespace std; #define ll long long const int INF = 0x3f3f3f3f; const int maxn = 2e6 + 10; /* 如果 S 是非规范的, 那么最小的反例小于两个最大面额的总和。 */ int dp[maxn]; int tx[maxn]; int main() { int n; cin>>n; int a[110]; int i,j; for(i=1; i<=n; i++) { cin>>a[i]; } int max_data=a[n]+a[n]; memset(dp,INF,sizeof(dp)); dp[0]=0; memset(tx,0,sizeof(tx)); for(i=1; i<=n; i++) { for(j= a[i] ; j<=max_data; j++) { if(i==1) { tx[j]=j/a[i]; dp[j]=j/a[i]; } else { tx[j]=tx[j-a[i] ]+1; dp[j]=min(dp[j-a[i] ]+1,dp[j]); } } } for(i=1; i<=max_data; i++) { //cout<<dp[i] if(dp[i]!=tx[i]) { cout<<"non-canonical"<<endl; return 0; } } cout<<"canonical"<<endl; return 0; }
J - Progressive Scramble
Kattis - progressivescramble
题意:
解密加密字符串
-
输入e表示加密,输入d则表示解码
-
加密的规则
-
- 是先给原字符一个对应的数,空格为0,字母从1开始对应直到26,一共27个合法字符。
-
- 从a[0]开始,将对应位置换为字符的前缀和,然后对前缀和%27,这个数对应的字符即为加密后的字符串。
-
解密就是逆向加密
思路:
模拟........
代码:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; int num[1005]; int sum[1005]; int main() { int t; cin>>t; getchar(); while(t--) { memset(num,0,sizeof(num)); memset(sum,0,sizeof(sum)); char c=getchar(); getchar(); string str,ans; getline(cin,str); for(int i=0;i<str.length();i++) { if(str[i]==' ') sum[i]=0; else sum[i]=str[i]-'a'+1; } if(c=='e') { for(int i=1;i<str.length();i++) sum[i]=(sum[i]+sum[i-1])%27; } else if(c=='d') { for(int i=1;i<str.length();i++) { num[i]=num[i-1]+sum[i-1]; while(sum[i]<num[i]) sum[i]+=27; sum[i]=(sum[i]-num[i])%27; } } for(int i=0;i<str.length();i++) if(sum[i]==0) ans+=' '; else ans+='a'+sum[i]-1; cout<<ans<<endl; } return 0; }
G - Greeting Card
Kattis - greetingcard
题意:
给一组点,统计所有点中,任选两个点距离为2018的有多少对。
思路1:
暴力..........马上否定,一定会超时
思路2:
如果两个点距离为2018
那么只能:
- x差2018,y相等
- x相等,y差2018
- x差1680,y差1118
- x差1118,y差1680。
四种情况,问题解决
代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> P; const int N=5e5+5; int n; map<P,int> m; ll sum; int add[12][2]={{2018,0},{-2018,0},{0,2018},{0,-2018},{1118,1680},{-1118,1680},{1118,-1680},{-1118,-1680},{1680,1118},{-1680,1118},{1680,-1118},{-1680,-1118}}; int main() { scanf("%d",&n); while(n--) { ll x,y; cin>>x>>y; sum+=m[P(x,y)]; for(int i=0;i<12;i++) m[P(x+add[i][0],y+add[i][1])]++; } cout<<sum<<endl; return 0; }
大神思路
- 按照每个点距离原点的距离排序,如果距原点之差大于2018,则停止
(运用的是三角形两边之差小于第三边)
考虑到在一条直线的情况后,就是大于2018而不是大于等于2018了。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+3; typedef unsigned long long ll ; struct Node { ll x, y; double len; friend bool operator < (Node &a,Node &b) { return a.len < b.len; } }node[maxn]; ll dis(Node a, Node b) { int x1 = max(a.x,b.x); int x2 = min(a.x,b.x); int y1 = max(a.y,b.y); int y2 = min(a.y,b.y); return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); } int main() { int n; cin>>n; for(int i = 0; i < n ;i++) { cin>>node[i].x>>node[i].y; node[i].len = sqrt(node[i].x*node[i].x+node[i].y*node[i].y); } sort(node,node+n); int ans = 0; ll base = 2018 * 2018;//精度问题,一定要比较乘方 for(int i = 0 ; i < n; i++) { for(int j = i+1 ;j < n; j++) { if(node[j].len-node[i].len > 2018) break; if(dis(node[i],node[j]) == base ) { ans++; } } } cout<<ans<<endl; return 0; }
F - GlitchBot
Kattis - glitchbot
题意:
机器人 刚开始在(0, 0),有一个目标点,
给一系列指令,但是其中会有一个指令是错误的。我们需要找出那个指令,并且改成正确的。
思路:
数据范围50.....
直接暴力:每条指令都改一下 搜索能不能走到目标点,如果可以,那么这就是答案
代码:
#include <bits/stdc++.h> using namespace std; int step[200]; int dx[] = {0 , 1 , 0 , -1};//上右下左顺序固定 int dy[] = {1 , 0 , -1 , 0}; int x_0,y_0,n; bool judge() { int direction = 0; int x = 0,y = 0; for(int i = 0 ; i < n; i++) { if(step[i] == 0) { x = x + dx[direction]; y = y + dy[direction]; } else if(step[i] == 1) direction = (direction + 3) % 4; else if(step[i] == 2) direction = (direction + 1) % 4; } return (x == x_0 && y == y_0); } int main() { cin>>x_0>>y_0>>n; string s; for(int i = 0; i < n; i++) { cin>>s; if(s[0] == 'F') step[i] = 0; else if(s[0] == 'L') step[i] = 1; else if(s[0] == 'R') step[i] = 2; } bool flag = 1; for(int i = 0 ; i < n && flag; i++) { for(int j = 0; j <= 2; j++) { step[i] = (step[i] + 1) % 3; //太精髓了吧。 if(judge()) { printf("%d ",i+1); if(step[i] == 0) cout<<"Forward"<<endl; else if(step[i] == 1) cout<<"Left"<<endl; else if(step[i] == 2) cout<<"Right"<<endl; flag = 0; break; } } } return 0; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/15191527.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步