CodeTON Round 1 (Div. 1 + Div. 2, Rated, Prizes)

本文提供了四道算法竞赛题目的解析及代码实现,包括寻找数组中的好对、通过操作使序列中最后一个元素为特定值、调整序列使所有元素相等以及K-good数的探讨。

昨晚状态不好, 翻车了,今天正序补题吧

A. Good Pairs

题意:给你一个数组 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1a2an 一个正整数数组。好的一对是一对指数 ( i , j ) (i,j) ij 1 ≤ i 、 j ≤ n 1≤i、 j≤n 1ijn 因此,对于所有 1 ≤ K ≤ n 1≤K≤n 1Kn、 以下等式成立:
∣ a i − a k ∣ + ∣ a k − a j ∣ ≥ ∣ a i − a j ∣ , |a_i−a_k|+|a_k−a_j|≥|a_i−a_j|, aiak+akajaiaj,

由三角不等式可以只当且仅当 m i n ( a i , a j ) ≤ a k ≤ m a x ( a i , a j ) ; min(a_i, a_j) ≤ a_k ≤ max(a_i,a_j); min(ai,aj)akmax(ai,aj);成立, 当然也可以分类讨论证明

#include<bits/stdc++.h>
#define x first
#define y second
typedef std :: pair<int, int> PII;
#define debug printf("debug\n");
#define gg exit(0);
#define int long long
const int N = 5e5 + 10;

using namespace std;
PII a[N];
void solve()
{
	int n;
	cin >> n;
	int  x;
	for(int i = 1; i <= n; i ++ ) cin >> x, a[i] = {x, i};

	sort(a + 1, a + 1 + n);   //排序

	cout << a[1].second << " " << a[n].second << '\n';  //最大值的下标和最小值的下标
}
signed main()
{
	 int t;
	 cin >> t;
	 while(t -- )
	 	solve();

}

B. Subtract Operation
题意: 你会得到一个 n n n 个整数的数列。可以执行以下操作:从数列中选择一个元素 x x x,从数列中删除 x x x ,然后从所有剩余元素中减去 x x x 的值。因此,在一次操作中,列表的长度正好减少了 1 1 1
给定一个整数 k k k ( k > 0 ) (k>0) k>0,找出是否有 n − 1 n - 1 n1 个操作,使得在应用这些操作之后,列表中唯一剩余的元素等于 k k k

我们可以枚举一种情况
a 1 , a 2 , a 3 a_1, a_2,a_3 a1,a2,a3
a 1 − a 2 , a 3 − a 2 a_1 - a_2, a_3 - a_2 a1a2,a3a2
a 3 − a 2 − a 1 + a 2 a_3 - a_2 - a_1 + a_2 a3a2a1+a2
a 3 − a 1 a_3 - a_1 a3a1

然后不难发现规律, 就是要找任意两项的差为 k k k 的情况,

这里可以用哈希, 也可以用双指针

#include<bits/stdc++.h>
#define x first
#define y second
typedef std :: pair<int, int> PII;
#define debug printf("debug\n");
#define gg exit(0);
#define int long long
const int N = 5e5 + 10;

using namespace std;
int a[N];
void solve()
{
	int n, k;
	map<int, int>st;
	cin >> n >> k;
	for(int i = 1; i <= n; i ++ ) cin >> a[i], st[a[i]] = 1; //记录是否存在这个数

	for(int i = 1; i <= n; i ++ )
		if(st[a[i] + k])  //如果存在差为k的
		{
			cout << "YES\n";
			return;
		}

	cout << "NO\n";

}
signed main()
{
	 int t;
	 cin >> t;
	 while(t -- )
	 	solve();

}

双指针

#include<bits/stdc++.h>
#define x first
#define y second
typedef std :: pair<int, int> PII;
#define debug printf("debug\n");
#define gg exit(0);
#define int long long
const int N = 5e5 + 10;

using namespace std;
int a[N];
void solve()
{
	 int n, k;
	 cin >> n >> k;
	 for(int i = 1; i <= n; i ++ ) cin >> a[i];
	 
	 sort(a + 1, a + 1 + n);
	 
	 if(n == 1) cout << (a[1] == k) ? "YES\n" : "NO\n";
	 else 
	 {
	     int i = 1, j = 2;
	     while(j <= n && i <= n )
	     {
	         if(a[j] - a[i] == k)
	         {
	             cout << "YES\n";
	             return;
	         }
	         else if(a[j] - a[i] > k) i ++;
	         else j ++;
	     }
	 }
    cout << "NO\n";
}
signed main()
{
	 int t;
	 cin >> t;
	 while(t -- )
	 	solve();

}

C. Make Equal With Mod

题意: 给定长度为 n n n 的序列 a a a, 每次选择一个大于等于 2 2 2 的数 x x x, 使得整个数列模上 x x x, 然后判断能否使得数列所有元素相等

分析: 首先如果序列中不存在 1 1 1, 是肯定能使得所有元素相等的,
其次 如果既存在 1 1 1 又存在 0 0 0, 因为存在 0 0 0 所以最后只能变成 0 0 0, 但是 1 1 1 又无法变成 0 0 0 (因为只能模 ≥ 2 ≥2 2 的数 ) 所以无解
最后我们如果既 存在 1 1 1, 又不存在 0 0 0, 那我们每次可以模上一个刚好比每一个数小 1 1 1 的数, 比如 5 5 5 变成 1 1 1, 我们可以模 4 4 4, 3 3 3 变成 1 1 1, 模 2 2 2, 但是这里有一种特殊情况, 如果既有 3 3 3 , 又有 4 4 4, 那么我们在模上 2 2 2 之后 4 4 4就变成了 0 0 0, 显然不符合要求, 所以我们必须保证没有连续的数字才合法, 如果存在连续的数字,则无解

#include<bits/stdc++.h>
#define x first
#define y second
typedef std :: pair<int, int> PII;
#define debug printf("debug\n");
#define gg exit(0);
#define int long long
const int N = 5e5 + 10;

using namespace std;
int a[N];
void solve()
{
	int n;
	cin >> n;
	map<int,int>st;
	for(int i = 1; i <= n; i ++ )
   {
		cin >> a[i];
		st[a[i]] = 1;  //记录状态
    }
   if(!st[1]) //无1
   {
    	cout << "YES\n";
    	return;
   }
   if(st[0])   //有1 有0
   {
 	    cout << "NO\n";
    	return;
   	} 
   	for(int i = 1; i <= n; i ++ )
   		if(st[a[i] + 1])  //连续
   	{
   		//gg
   			cout << "NO\n";
   			return;
   	}
   	  cout << "YES\n";

}
signed main()
{
	 int t;
	 cin >> t;
	 while(t -- )
	 	solve();

}

D. K-good

数论, 不会, 摆烂了

E题有机会再补吧

import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Random; public class LuckyDrawWheel extends JFrame { private String[] prizes = {"一等奖", "二等奖", "三等奖", "谢谢参与", "再来一次", "优惠券"}; private int[] angles = new int[prizes.length]; private int currentAngle = 0; private boolean isSpinning = false; private JButton startButton; private JPanel wheelPanel; public LuckyDrawWheel() { setTitle("幸运大转盘"); setSize(500, 500); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(new BorderLayout()); // 计算每个奖项的角度(均分360度) int anglePerPrize = 360 / prizes.length; for (int i = 0; i < prizes.length; i++) { angles[i] = anglePerPrize; } wheelPanel = new JPanel() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); drawWheel(g); } }; startButton = new JButton("开始抽奖"); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (!isSpinning) { startSpin(); } } }); add(wheelPanel, BorderLayout.CENTER); add(startButton, BorderLayout.SOUTH); } private void drawWheel(Graphics g) { int centerX = getWidth() / 2; int centerY = getHeight() / 2; int radius = Math.min(centerX, centerY) - 20; // 1. 绘制色块(先画色块,再画文字,避免文字被覆盖) int startAngle = currentAngle; for (int i = 0; i < prizes.length; i++) { g.setColor(getColor(i)); g.fillArc( centerX - radius, centerY - radius, radius * 2, radius * 2, startAngle, angles[i] ); startAngle += angles[i]; } // 2. 绘制文字(核心修正:调整旋转角度) startAngle = currentAngle; for (int i = 0; i < prizes.length; i++) { drawText(g, prizes[i], centerX, centerY, radius, startAngle + angles[i] / 2); startAngle += angles[i]; } // 3. 绘制指针 g.setColor(Color.BLACK); Polygon pointer = new Polygon(); pointer.addPoint(centerX, centerY - radius - 10); pointer.addPoint(centerX - 10, centerY - radius + 10); pointer.addPoint(centerX + 10, centerY - radius + 10); g.fillPolygon(pointer); } // 修正文字旋转逻辑的核心方法 private void drawText(Graphics g, String text, int centerX, int centerY, int radius, int angle) { Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.BLACK); g2d.setFont(new Font("微软雅黑", Font.BOLD, 16)); // 计算文字在扇形中的坐标 double radian = Math.toRadians(angle); int textX = centerX + (int) (radius * 0.5 * Math.sin(radian)); int textY = centerY - (int) (radius * 0.5 * Math.cos(radian)); // 关键修正:让文字“垂直”贴合扇形,旋转角度 = 扇形中间角度 - 90度 double rotateAngle = radian - Math.toRadians(90); FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.stringWidth(text); // 先旋转画布,再绘制文字,最后旋转回来 g2d.rotate(rotateAngle, textX, textY); g2d.drawString(text, textX - textWidth / 2, textY); g2d.rotate(-rotateAngle, textX, textY); } // 随机颜色(可自定义更贴合实物的颜色) private Color getColor(int index) { Color[] colors = { Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.ORANGE, Color.CYAN }; return colors[index % colors.length]; } // 转盘转动逻辑(线程控制) private void startSpin() { isSpinning = true; startButton.setEnabled(false); Random random = new Random(); final int spinRounds = 5 + random.nextInt(5); // 5-9圈 final int targetAngle = random.nextInt(360); // 最终停留角度 new Thread(() -> { try { int totalRotation = 360 * spinRounds + targetAngle; int step = 10; // 初始步长 for (int i = 0; i < totalRotation; i += step) { currentAngle = (currentAngle + step) % 360; Thread.sleep(20); wheelPanel.repaint(); // 逐渐减速(模拟物理效果) if (i > totalRotation * 0.7) { step = (int) (step * 0.95); if (step < 1) step = 1; } } // 计算获奖奖项 int prizeIndex = (360 - currentAngle) / (360 / prizes.length); prizeIndex = prizeIndex % prizes.length; JOptionPane.showMessageDialog( LuckyDrawWheel.this, "恭喜您获得: " + prizes[prizeIndex] ); } catch (InterruptedException e) { e.printStackTrace(); } finally { isSpinning = false; startButton.setEnabled(true); } }).start(); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> new LuckyDrawWheel().setVisible(true)); } } 让文字旋转方向与扇形一致
最新发布
06-25
在你当前的 Java Swing 转盘抽奖程序中,**文字是通过旋转画布来绘制的,但旋转角度计算不正确**,导致: > ✅ **扇形顺时针旋转,而文字逆时针旋转或方向错乱** --- ## ✅ 问题分析 在 `drawText(...)` 方法中,你使用了如下方式旋转画布来绘制文字: ```java double rotateAngle = radian - Math.toRadians(90); g2d.rotate(rotateAngle, textX, textY); g2d.drawString(text, textX - textWidth / 2, textY); g2d.rotate(-rotateAngle, textX, textY); ``` 这里的 `radian` 是基于当前扇区中心角度的弧度值。你减去了 `90°` 并旋转画布,但这会导致文字与扇形的旋转方向不一致。 --- ## ✅ 解决方案 要让**文字始终贴合扇形并跟随其旋转方向**,我们需要: - 文字也随整个转盘一起旋转; - 使用相同的旋转基准角(即 `currentAngle`); - 确保每次绘制文字时都以正确的角度旋转。 --- ## ✅ 修改后的 `drawText()` 方法如下: ```java private void drawText(Graphics g, String text, int centerX, int centerY, int radius, int angle) { Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.BLACK); g2d.setFont(new Font("微软雅黑", Font.BOLD, 16)); // 计算文字位置:位于扇区半径的中间位置 double radian = Math.toRadians(angle); int textX = centerX + (int)(radius * 0.6 * Math.cos(radian)); int textY = centerY + (int)(radius * 0.6 * Math.sin(radian)); // 计算字体宽度和高度,用于居中显示 FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.stringWidth(text); int textHeight = fm.getHeight(); // 设置旋转角度:使文字面向扇区内部,并保持与扇形一致的旋转方向 double rotateAngle = radian; // 使用 AffineTransform 实现局部旋转,避免影响其他绘制内容 AffineTransform oldTransform = g2d.getTransform(); g2d.rotate(rotateAngle, textX, textY); g2d.drawString(text, textX - textWidth / 2, textY + textHeight / 4); // 微调垂直偏移 g2d.setTransform(oldTransform); // 恢复原始变换 } ``` --- ## ✅ 效果说明 | 原始问题 | 修改后效果 | |----------|-------------| | 文字旋转方向与扇形不同步 | ✅ 文字始终与扇形同步旋转 | | 文字位置不在扇区中心 | ✅ 文字准确居于每个扇区中心 | | 文字被裁剪或显示不全 | ✅ 文字大小适配合理半径距离 | --- ## ✅ 可选增强:让文字自动换行适应长文本 如果你希望支持更长的奖项名称(如“恭喜获得价值500元优惠券”),可以使用以下方法实现自动换行: ```java private void drawMultiLineText(Graphics g, String text, int centerX, int centerY, int radius, int angle) { Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.BLACK); g2d.setFont(new Font("微软雅黑", Font.BOLD, 14)); double radian = Math.toRadians(angle); int textX = centerX + (int)(radius * 0.6 * Math.cos(radian)); int textY = centerY + (int)(radius * 0.6 * Math.sin(radian)); FontMetrics fm = g2d.getFontMetrics(); int maxCharsPerLine = 6; // 每行最多字符数 AffineTransform oldTransform = g2d.getTransform(); g2d.rotate(radian, textX, textY); for (int i = 0; i < text.length(); i += maxCharsPerLine) { int end = Math.min(i + maxCharsPerLine, text.length()); String line = text.substring(i, end); int y = textY + (i / maxCharsPerLine) * fm.getHeight(); g2d.drawString(line, textX - fm.stringWidth(line) / 2, y); } g2d.setTransform(oldTransform); } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

广西小蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值